Теперь создайте пункт меню на статью "Отзывы".
В папке modules/article/model/commenttype создайте файл feedback.inc.php
В СТРОКЕ с текстом 

return 20;//страница отзывов

замените 20 на id статьи "Отзывы".

<?php
/**
* ReadyScript (http://readyscript.ru)
*
* @copyright Copyright (c) ReadyScript lab. (http://readyscript.ru)
* @license http://readyscript.ru/licenseAgreement/
*/
namespace evAddons\Model\CommentType;
//to do
//1.Вынести настройки в модуль
/**
* Тип комментария - коментарий к статье
* @ingroup Article
*/
class Feedback extends \Comments\Model\Abstracttype
{
    /**
    * Возвращает тип комментария
    */
    function getTitle()
    {
        return t('Отзывы');
    }
    
    /**
    * Возвращает ссылку на объект в административной части
    * 
    * @return string
    */
    function getAdminUrl(\Comments\Model\Orm\Comment $comment)
    {
        return \RS\Router\Manager::obj()->getAdminUrl('edit', array('id' => $comment['aid']), 'article-ctrl');
    }    
    
    /**
    * Возвращает id товара, к которому необходимо привязать комментарий
    * 
    * @return integer
    */
    function getLinkId()
    {
        $route = \RS\Router\Manager::obj()->getCurrentRoute();
       //убираем проверку на маршрут    
       
          if (isset($route->article_id)) {
                return $route->article_id;
            }
        
        return 20;//страница отзывов
  //return 9999;
    }
    
    /**
    * Обновляет поле "рейтинг" у статьи
    * Вызывается при добавлении комментария
    */
    function onAdd(\Comments\Model\Orm\Comment $comment)
    {
        if ($comment['rate']) {
            $api    = new \Comments\Model\Api(); 
            $api->recountItemRatingByComment(new \Article\Model\Orm\Article(), $comment);
        }
        return true;
    }
    
    /**
    * Действие при удалении комментария
    */
    function onDelete(\Comments\Model\Orm\Comment $comment)
    {
        $api = new \Comments\Model\Api(); 
        $api->recountItemRatingByComment(new \Article\Model\Orm\Article(), $comment);
    }
}

В папке moduleview/article  с вашей темой создайте файл view_article_feedback.tpl

<div class="newsView">
    <article>
        <h1>{$article.title}</h1>
        
        {if !empty($article.image)}
        <img class="mainImage" src="{$article.__image->getUrl(700, 304, 'xy')}" alt="{$article.title}"/>
        {/if}
        {$article.content}
    </article>
    {moduleinsert name="\Photo\Controller\Block\PhotoList" type="article" route_id_param="article_id"}
    
</div>
{moduleinsert name="\Comments\Controller\Block\Comments" type="Article\Model\CommentType\Feedback"}

В конструкторе сайта создайте страницу "Меню-ОТзывы", поместите туда блок "Статья" со статьей "Отзывы", а шаблон в настройка замените на "theme:<Ваша тема>/moduleview/article/view_article_feedback.tpl"

Теперь у нас в админке есть комментарии с типом "Отзывы" на странице "Отзывы")))

Это слишком узконаправленный функционал.  Чтобы всех удовлетворить, тогда надо делать конструктор фильтров, как сделано, например у Oracle Forms.
В понедельник запрос напишу и выложу.

Облако или на Вашем хостинге?
Если на хостинге, то простейшими sql запросами можно вывести список.
А можно и модуль фильтра каталога товаров сделать. В платной техподдержке за день-два сделают.

554

(2 ответов, оставленных в Вопросы по работе с системой)

Как вариант, сначала разрабатывать на поддомене с активированной  на него лицензией (dev.site.ru). После переноса на site.ru попросить разработчиков активировать на основной домен.

Я реализовавыл данный функционал Оказывается блок комментариев предназначен только для новостей)
http://forum.readyscript.ru/topic/483/v … mentariev/ вот обсуждение.
Пришлось добавить новый тип комментариев- отзывы.
http://forum.readyscript.ru/post/2010/#p2010
В понедельник выложу свой вариант.

Как раз идея для модуля

557

(6 ответов, оставленных в Вопросы по работе с системой)

Попробуйте со стороны 1с сделать доработку.

Реклама?

559

(6 ответов, оставленных в Вопросы по работе с системой)

Решается просто.  В моделе надо навесить обработку события на сохранение товара и на окончание импорта 1с (чтобы раскидать по спецкатегориям, например).

  function init()
    {
        $this
            
            ->bind('exchange.gate.afterimport.all')//событие после импорта 1c
            ->bind('orm.beforewrite.catalog-product');//перехватываем сохранение товара
                           
    }
       

Пример для простановки даты создания товара. Аналогично тут можно сравнить старую и новую цену и сделать еще что-либо

public static function ormBeforewriteCatalogProduct(array $params, \RS\Event\Event $event)
    {
        if ($params['flag'] == \RS\Orm\AbstractObject::INSERT_FLAG) { //Если это добавление товара
            /**
            * Получаем из параметра ORM объект
            * @var \Catalog\Model\Orm\Product
            */
             $product = $params['orm'];
             if (!isset($product->dateof)) $product->dateof=date('Y-m-d H:i:s') ;
                         
           }
    }    

Вот пример того, как раскидать товары по спецкатегориям:

 
     public static function exchangeGateAfterimportAll()

    {  
        $router = \RS\Router\Manager::obj();
       
    
         if (\Setup::$INSTALLED) {
           $config = \RS\Config\Loader::byModule('users');
            $new_days  = 20;//$config['new_days']; пусть будет 20 дней
            $dir_new=2;//id спецкатегории "новинки"
    
             ///добавляем товары в спецкатегории
               //удалим связи с новинками 
              \RS\Orm\Request::make()
                    ->delete()              
                    ->from(new \Catalog\Model\Orm\Xdir()) 
                    ->where("dir_id in (".$dir_new.")")
                    ->exec();

             $xdir_table =  \RS\Orm\Tools::getTable( new \Catalog\Model\Orm\Xdir() ); 
                      $product_table = \RS\Orm\Tools::getTable( new \Catalog\Model\Orm\Product() );
            

                      \RS\Db\Adapter::sqlExec( "INSERT IGNORE INTO {$xdir_table} (product_id, dir_id) SELECT wp.id,{$dir_new} FROM {$product_table} wp WHERE  TO_DAYS(NOW()) - TO_DAYS(wp.dateof) <= ".$new_days);
             
         
                                    
            
        }
      
    }

На текущий момент жалоб нет. Правда я перестраховался и добавил 1 процессор в VDS.

561

(11 ответов, оставленных в Вопросы по разработке модулей и API системы)

1. Начало оформления заказа    url: содержит «/checkout/address»
2. Страница оплаты    url: содержит «/checkout/payment/»
3. Подтверждение заказа    url: содержит «/checkout/confirmpage/»
4. Заказ совершен    url: содержит «/checkout/finish/»

Отдельная обработка событий метрики удобна тем, что можно сделать свой модуль, который будет подключаться к существующей теме без переделки.
На самом деле, подглядел у одного известного движка) Но там модуль еще и сам создавал цели в Метрике через API.

Александр, версия не последняя. Модуль магазина 2.0.0.86 .  Вопрос о необходимости обновления я поднял перед заказчиком. Но когда все работает, кроме данного момента, трогать как то не хочется)))
==========
Комплектации не используют, скидок нет (привязываются типы цен к пользователям), сопутствующих нет.
В зависимости от количества товара в корзине, или долгий ответ или превышается лимит выполнения скрипта(я поднял выше стандартного).
Все три пункта))

Раз не доходит и до адреса, значит где то в actionIndex() контроллера заказа рубится.
Пока закомментировал сопутствующие и склеивание одинаковых.

 function actionIndex()
    {
        $this->order->clear();
                 
        //Замораживаем объект "корзина" и привязываем его к заказу
        $frozen_cart = \Shop\Model\Cart::preOrderCart(null);
        //eventus нет сопутcтвующих
        //$frozen_cart->splitSubProducts();
        //$frozen_cart->mergeEqual();
        
        $this->order->linkSessionCart($frozen_cart);
        $this->order->setCurrency( \Catalog\Model\CurrencyApi::getCurrentCurrency() );
        $this->order['ip'] = $_SERVER['REMOTE_ADDR'];
        $this->order['expired'] = false;
        $this->redirect($this->router->getUrl('shop-front-checkout', array('Act' => 'address')));
    }

p.s.
Возможны ли дополнительные проблемы с нагрузкой из-за постоянного вызова deleteExpiredCartItems при добавлении в корзину? Оптовики как из пулемета "нащелкивают" товар в корзину)

Здравствуйте! Тут столкнулся с проблемной. Оптовый магазин канцелярки.
Имеются клиенты, которые кладут в корзину от 200 до 500 наименований товаров.
И при оформлении заказа сажают сервер (хотя выводит сообщение о необходимости дробить заказы)
Прямо после нажатия на "Оформить заказ" в корзине.
Сейчас конфигурация 4 ядра, 1 гб ОЗУ. На сервере только 1 сайт.
Количество товаров около 5000,  заказов в день около 25.

Что можно оптимизировать?

Как вариант, можно  запретить класть в корзину более 60 наименований.

Петр, в RS достаточно гибкое меню, особенно  вместе с возможностью подгружать в шаблонах дополнительные модули функцией moduleinsert.  Подробнее в документации разработчика:
1. В список категорий вставляет меню:

{* Вставляет в шаблон блок Меню, в котором будут отображаться дочерние элементы от элемента с символьным идентификатором footmenu*}
{moduleinsert name="\Menu\Controller\Block\Menu" root="footmenu"}

2.В шаблон меню список категорий:

{* Вставляет в шаблон блок Список категорий *}
{moduleinsert name="\Catalog\Controller\Block\Category"}

Еще вариант:
3. просто решаете задачу в лоб, просто добавив ссылки, если их не очень много:

<ul class="topMenu" id="topMenu">
    {foreach $dirlist as $dir}
    <li class="item_{$dir@iteration}{if !empty($dir.child)} node{/if}" {$dir.fields->getDebugAttributes()}><a href="{$dir.fields->getUrl()}">{$dir.fields.name}</a>
        {if !empty($dir.child)}
            {$cnt=count($dir.child)}
            {$columns=1}
            {if $cnt>3}{$columns=2}{/if}
            {if $cnt>6}{$columns=3}{/if}
            {if $cnt>12}{$columns=4}{/if}
            {* Второй уровень *}
            <ul class="columns{$columns}">
                {foreach $dir.child as $subdir}
                <li><a href="{$subdir.fields->getUrl()}">{$subdir.fields.name}</a>
                    {if !empty($subdir.child)}
                    {* Третий уровень *}
                    <ul>
                        {foreach $subdir.child as $subdir2}
                        <li><a href="{$subdir2.fields->getUrl()}">{$subdir2.fields.name}</a></li>
                        {/foreach}
                    </ul>
                    {/if}
                </li>
                {/foreach}
            </ul>
        {/if}
    </li>
    {/foreach}
       <li class="second_item"><a href="/catalog/new/">Новинки <i class="fa fa-truck"></i></a>
       </li>
       <li class="second_item"><a href="/catalog/akcii/">Акции <i class="fa fa-gift"></i></a>
       </li>
       <li class="second_item"><a href="/catalog/last/">Последние поступления <i class="fa fa-clock-o "></i></a>
       </li>
       <li class="second_item"><a href="/feedback/">Отзывы <i class="fa fa-thumbs-o-up"></i></a>
       </li>
       
   </ul>

Возможно ли модулем переопределить данную функцию?
Просьба к администраторам перенести эту раздел "Вопросы по разработке модулей и API системы"

Здравствуйте!
Используем многомерные комплектации.
Если у товара имеется 1 размер , то при выгрузке в 1с не проставляется xml_id товарного предложения ("Ид" в выгрузке)
и в документе в 1с выводится Носки m0e0107-0055 BNM без указания размера (не подтягивается товарное предложение)
Файл выгрузки:

 - <Товар>
  <Ид>ca20582e-d532-11e4-996d-dc85deaed994</Ид> 
  <Наименование>Носки m0e0107-0055 BNM, Носки m0e0107-0055 BNM (42-45)</Наименование> 
  <БазоваяЕдиница Код="796" НаименованиеПолное="" МеждународноеСокращение="PCE">шт.</БазоваяЕдиница> 
  <ЦенаЗаЕдиницу>80</ЦенаЗаЕдиницу> 
  <Количество>12</Количество> 
  <Сумма>960</Сумма> 
- <ЗначенияРеквизитов>
- <ЗначениеРеквизита>
  <Наименование>ВидНоменклатуры</Наименование> 
  <Значение>Товар</Значение> 
  </ЗначениеРеквизита>
- <ЗначениеРеквизита>
  <Наименование>ТипНоменклатуры</Наименование> 
  <Значение>Товар</Значение> 
  </ЗначениеРеквизита>
  </ЗначенияРеквизитов>
  </Товар>

Пришлось закомментировать часть кода в modules\exchange\model\api.inc.php:

 /**
    * Получает xml_id товарного предложения по товару
    * 
    * @param \Shop\Model\Orm\OrderItem $offer_product - объект товара в заказе
    * @param \Catalog\Model\Orm\Product $product      - объект связанного товара
    * @return string
    */
    private function getOfferXmlIdByOfferProduct(\Shop\Model\Orm\OrderItem $offer_product, $product){
        $xml_id = $product->xml_id; //Получаем xml_id 
        
       // if ($offer_product['offer'] && $product){ //Если комплектация отличная от оригинала !ТУТ!
            $product->fillOffers();
            
            if ($product->isOffersUse()){ //Если такое предложение есть
                $offer = $product['offers']['items'][$offer_product['offer']];
                return $offer['xml_id'];
            }
        //}       !И ТУТ!
        return $xml_id;
    }

Стало выводится верно

 <Товар>
  <Ид>ca20582e-d532-11e4-996d-dc85deaed994#ca205832-d532-11e4-996d-dc85deaed994</Ид> 
  <Наименование>Носки m0e0107-0055 BNM, Носки m0e0107-0055 BNM (42-45)</Наименование> 
  <БазоваяЕдиница Код="796" НаименованиеПолное="" МеждународноеСокращение="PCE">шт.</БазоваяЕдиница> 
  <ЦенаЗаЕдиницу>80</ЦенаЗаЕдиницу> 
  <Количество>132</Количество> 
  <Сумма>10560</Сумма> 
- <ЗначенияРеквизитов>
- <ЗначениеРеквизита>
  <Наименование>ВидНоменклатуры</Наименование> 
  <Значение>Товар</Значение> 
  </ЗначениеРеквизита>
- <ЗначениеРеквизита>
  <Наименование>ТипНоменклатуры</Наименование> 
  <Значение>Товар</Значение> 
  </ЗначениеРеквизита>
  </ЗначенияРеквизитов>
  </Товар>

с последнего обновления код немного другой. Перестал передаваться article_id, вывожу напрямую id статьи

function getLinkId()
    {
        //$route = \RS\Router\Manager::obj()->getCurrentRoute();
         //отсюда убираем проверку идентификатора маршрута
         //if (isset($route->article_id)) {
         //    return $route->article_id;
        // }
        return 20; //здесь идетификатор Вашей статьи "Отзывы"
    }

568

(1 ответов, оставленных в Вопросы по работе с системой)

С наступающим Новым годом!
Спасибо огромное вашей команде за проделанную работу!
Счастья, здоровья вам и вашим семьям! Отлично встретить Новый и проводить старый год!
И, конечно, дальнейшего развития ReadyScript!

569

(21 ответов, оставленных в Вопросы по работе с системой)

Можно еще вставить ссылку вместо просто текста "цену по запросу" на вывод формы обратной связи.

570

(12 ответов, оставленных в Вопросы по Маркетплейсу)

Как вариант, просто отдельная категория в каталоге "Портфолио" и вместо товаров выполненные работы.

571

(12 ответов, оставленных в Вопросы по Маркетплейсу)

Или можно решить задачу в лоб, сверстав html страницу с фото и добавив ее в статью.

572

(8 ответов, оставленных в Вопросы по Маркетплейсу)

Как то была подобная задача.
Решил следующим путем.
Настроил несколько типов цен для соответствующей скидки.


Создал (спасибо разработчикам за советы) простой модуль.
Тип цены переключается в зависимости от суммы товаров в корзине:

<?php

namespace Opt\Config;

class Handlers extends \RS\Event\HandlerAbstract
{
    function init()
    {
        $this->bind('cart.update.after')
               ->bind('cart.getcartdata')
              ->bind('cart.addproduct.after'); 
    }    
    
   public static function checkprice($info)
    {
         //\Catalog\Model\CostApi::setSessionDefaultCost(2); 
          if (!$_SESSION['user_cost_id']) {
                $_SESSION['user_default_cost_id']=\Catalog\Model\CostApi::getDefaultCostId();
                $cost_id=\Catalog\Model\CostApi::getDefaultCostId() ;
         }  
           else   $cost_id=$_SESSION['user_cost_id'];
                                                    
         $cart=$info['cart'];      
         $cartinfo = $cart->getCartData(false,false);
         flog($cost_id);                                
         flog( $cartinfo['total']);   
  //здест условие для переключения типа цены        
         if ((  $cartinfo['total']<50000) &&( $cost_id!=1)) 
         {       

             $_SESSION['user_cost_id']=1;    
               
             //здесь необходимо обновить корзину  
             //Заменим закешированный _current_cost_id у объекта товара 
            
            foreach($cart->getProductItems() as $cartdata) {  
             
                $cartdata['product']['_current_cost_id'] =1;
            }

            //Очистим сведения для блока корзины
            $cart->cleanInfoCache();
 
             $info['cart']=$cart;           
             
        }
///здесь условие для переключения типа цены
         elseif ((  $cartinfo['total']>=50000)&&( $cost_id!=2)) 
         {       
             
              $_SESSION['user_cost_id']=2;  
              
              //здесь необходимо обновить корзину 
              //Заменим закешированный _current_cost_id у объекта товара
            foreach($cart->getProductItems() as $cartdata) {
            
                $cartdata['product']['_current_cost_id'] =2; 
                
            }

            //Очистим сведения для блока корзины
            $cart->cleanInfoCache();
 
             $info['cart']=$cart;   
            
         };
      
         $info['cost_id']= $_SESSION['user_cost_id'];        
       return $info;    
    }
  public static function cartUpdateAfter ($info)
    {  
    
       $result=self::checkprice($info);           
       return $result;     
           
    }
   public static function cartGetcartdata ($info)
   {     
     
     $k=$info['cart_result'];     
     $k['cost_id']= $_SESSION['user_cost_id'];  

     return $info ;
   }   
                           
   public static function cartAddproductAfter ($info)
    {  
           $result=self::checkprice($info);           
          return $result;
    }
    
}

Я подключил выделенные IP. Иначе никак. По опыту, в основном и взламывали то сайты из-за утекших или полученных перебором паролей к фтп.
Для безопасности 100-150 рублей не деньги, зато эффект на тысячи.
Так же можно настроить фтп-сервер,чтобы блокировал перебор паролей

1. В основном запрещаю ftpaccess доступ по фтп (кроме наших айпи)
2. Резервное копирование базы несколько раз в день средствами панели ISPManager (можно использовать sypex backup)
Раз в неделю копирование всего сайта на удаленный фтп-сервер.

Спасибо! Сам не знал)))