27 March 2012

Product Ratings Suite v1.6

A complete ratings package for your 1.4 PrestaShop store.

Allow customers/visitors to rate products. Add a BO Stats page and FO Block to show the best rated products.

- Ratings of Products in AJAX v0.97
- Best Rated Products BO Stats v1.2
- Best Rated Products FO Block v1.5
FREE Download
CHANGELOG:
v1.6 (2012-03-27)
[+] Added option to include Google Rich Snippets. (productrating)
v1.5 (2012-03-16)
[+] Added option to exclude products not available to order. (blockbestrated)
v1.4 (2011-07-14)
[*] Fixed missing quotes on database table name. (productrating)
v1.3 (2011-06-01)
[*] Moved included JS/CSS calls to header hook and added page recognition. (productrating)
v1.2 (2011-04-13)
[+] Added category related rated products when on product page. (blockbestrated)
v1.1 (2011-04-06)
[*] Fixed ratings for friendly urls. (productrating)
v1.0 (2011-03-27)
[+] First release of re-packaged 1.4 modules to the PrestaShop community.

4 January 2012

Search by Tracking Number v1.0

Adds a feature to the BO to search for tracking/shipping numbers.
#
#----------[ OPEN ]----------
#
admin/header.php

#
#----------[ FIND ]----------
#
      <option value="4" '.(Tools::getValue('bo_search_type') == 4 ? 'selected="selected"' : '').'>'.translate('invoices').'</option>


#
#----------[ BEFORE, ADD ]----------
#
      <option value="8" '.(Tools::getValue('bo_search_type') == 8 ? 'selected="selected"' : '').'>'.translate('tracking numbers').'</option>
#
#----------[ OPEN ]----------
#
admin/tabs/AdminSearch.php

#
#----------[ FIND ]----------
#
 function postProcess()

#
#----------[ BEFORE, ADD ]----------
#
 /**
 * Search a shipping number in the orders 
 *
 * @params string $query String to find in the catalog
 */
 public function searchShippingNumber($query)
 {
  $this->_list['shipping_numbers'] = Order::searchByShippingNumber($query);
 }

#
#----------[ FIND ]----------
#
   /* IP */
   // 6 - but it is included in the customer block

#
#----------[ AFTER, ADD ]----------
#
   /* Shipping Number */
   if (!$searchType OR $searchType == 8)
   {
    $this->fieldsDisplay['shipping_numbers'] = (array(
     'ID' => array('title' => $this->l('Order #')),
     'shipping_number' => array('title' => $this->l('Tracking #')),
     'customer' => array('title' => $this->l('Name')),
     'address1' => array('title' => $this->l('Address')),
     'city' => array('title' => $this->l('Suburb')),
     'state' => array('title' => $this->l('State')),
     'postcode' => array('title' => $this->l('Postcode')),
     'country' => array('title' => $this->l('Country')),
     'phone' => array('title' => $this->l('Phone')),
     'date' => array('title' => $this->l('Delivery Date')),
     'actions' => array('title' => $this->l('View'))
    ));

    /* Normal shipping number search */
    $this->searchShippingNumber($query);
   }

#
#----------[ FIND ]----------
#
  $nbCategories = $nbProducts = $nbCustomers = 0;

#
#----------[ REPLACE WITH ]----------
#
  $nbCategories = $nbProducts = $nbCustomers = $nbShippingNumbers = 0;

#
#----------[ FIND ]----------
#
  /* Display error if nothing has been matching */
  if (!$nbCategories AND !$nbProducts AND !$nbCustomers)

#
#----------[ REPLACE WITH ]----------
#
  /* Display shipping numbers if any has been matching */
  if (isset($this->_list['shipping_numbers']) AND !empty($this->_list['shipping_numbers']) AND $nbShippingNumbers = sizeof($this->_list['shipping_numbers']))
  {
   echo '<h3>'.$nbShippingNumbers.' '.($nbShippingNumbers > 1 ? $this->l('tracking numbers') : $this->l('tracking number')).' '.$this->l('found with').' <b>"'.Tools::htmlentitiesUTF8($query).'"</b></h3>
   <table cellspacing="0" cellpadding="0" class="table widthfull">
    <tr>';
   foreach ($this->fieldsDisplay['shipping_numbers'] AS $field)
    echo '<th'.(isset($field['width']) ? 'style="width: '.$field['width'].'"' : '').'>'.$field['title'].'</th>';
   echo '</tr>';
   $irow = 0;
   foreach ($this->_list['shipping_numbers'] AS $k => $shipping_number)
   {
    $carrier = new Carrier($shipping_number['id_carrier']);
    echo '
    <tr class="'.($irow++ % 2 ? 'alt_row' : '').'">
     <td>'.$shipping_number['id_order'].'</td>
     <td>'.$shipping_number['shipping_number'].'</td>
     <td>'.stripslashes($shipping_number['firstname']).' '.stripslashes($shipping_number['lastname']).'</td>
     <td>'.$shipping_number['address1'].'</td>
     <td>'.$shipping_number['city'].'</td>
     <td>'.$shipping_number['state'].'</td>
     <td class="center">'.$shipping_number['postcode'].'</td>
     <td>'.$shipping_number['country'].'</td>
     <td>'.($shipping_number['phone_mobile'] ? $shipping_number['phone_mobile'] : $shipping_number['phone']).'</td>
     <td align="center">'.Tools::displayDate($shipping_number['delivery_date'], (int)$cookie->id_lang, true).'</td>
     <td class="center" width="40px">
      <a href="'.str_replace('@', $shipping_number['shipping_number'], $carrier->url).'" target="_blank">
      <img src="../img/admin/supplier.gif" alt="'.$this->l('Track order').'" /></a>
      <a href="'.$currentIndex.'?tab=AdminOrders&id_order='.$shipping_number['id_order'].'&vieworder&token='.Tools::getAdminToken('AdminOrders'.(int)(Tab::getIdFromClassName('AdminOrders')).(int)($cookie->id_employee)).'">
      <img src="../img/admin/details.gif" alt="'.$this->l('View order').'" /></a>
     </td>
    </tr>';
   }
   echo '</table>
   <div class="clear">&nbsp;</div>';
  }
   
  /* Display error if nothing has been matching */
  if (!$nbCategories AND !$nbProducts AND !$nbCustomers AND !$nbShippingNumbers)
#
#----------[ OPEN ]----------
#
classes/Order.php

#
#----------[ FIND ]----------
#
 public function deleteAssociations()
 {
  return (Db::getInstance()->Execute('
    DELETE FROM `'._DB_PREFIX_.'order_detail`
    WHERE `id_order` = '.(int)($this->id)) !== false);
 }

#
#----------[ AFTER, ADD ]----------
#
 /**
   * Light back office search for shipping numbers
   *
   * @param string $query Searched string
   * @return array Corresponding shipping number
   */
 public static function searchByShippingNumber($query)
 {
  global $cookie;

  return Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('
  SELECT o.`shipping_number`, o.`id_order`, o.`delivery_date`, o.`id_carrier`, a.`firstname`, a.`lastname`, a.`address1`, a.`city`, a.`postcode`, a.`phone_mobile`, a.`phone`, s.`name` as state, cl.`name` as country 
  FROM `'._DB_PREFIX_.'orders` o
  LEFT JOIN `'._DB_PREFIX_.'address` a ON (a.`id_address` = o.`id_address_delivery`)
  LEFT JOIN `'._DB_PREFIX_.'state` s ON (s.`id_state` = a.`id_state`)
  LEFT JOIN `'._DB_PREFIX_.'country_lang` cl ON (cl.`id_country` = a.`id_country` AND cl.`id_lang` = '.(int)($cookie->id_lang).')
  WHERE o.shipping_number LIKE \'%'.pSQL($query).'%\'
  ORDER BY o.`shipping_number` DESC');
 }

31 December 2011

No. Units Sold for Stats Forecast Category Distribution table v1.0

Adds the number of units sold to the Stats Forecast Category Distribution table.
#
#----------[ OPEN ]----------
#
modules/statsforecast/statsforecast.php

#
#----------[ FIND ]----------
#
    <tr><th style="width:50px">'.$this->l('Category').'</th><th>'.$this->l('Count').'</th><th>'.$this->l('Sales').'</th><th>'.$this->l('% Count').'</th><th>'.$this->l('% Sales').'</th><th>'.$this->l('Avg price').'</th></tr>';

#
#----------[ REPLACE WITH ]----------
#
    <tr><th style="width:50px">'.$this->l('Category').'</th><th>'.$this->l('Count').'</th><th>'.$this->l('Units').'</th><th>'.$this->l('Sales').'</th><th>'.$this->l('% Count').'</th><th>'.$this->l('% Sales').'</th><th>'.$this->l('Avg price').'</th></tr>';

#
#----------[ FIND ]----------
#
     <td align="right">'.$catrow['orderQty'].'</td>

#
#----------[ AFTER, ADD ]----------
#
     <td align="right">'.$catrow['unitsSold'].'</td>

#
#----------[ FIND ]----------
#
COUNT(*) AS orderQty, 

#
#----------[ AFTER, ADD ]----------
#
SUM(od.`product_quantity`) AS unitsSold,

26 November 2011

Back Link & Date for Stock Movement Tab v1.0

Add a "Back to list" link & date column to BO stock movement tab.
#
#----------[ OPEN ]----------
#
admin/tabs/AdminStockMvt.php

#
#----------[ FIND ]----------
#
'employee' => array('title' => $this->l('Employee'), 'width' => 100, 'havingFilter' => true),

#
#----------[ AFTER, ADD ]----------
#
'date_add' => array('title' => $this->l('Date'), 'width' => 60, 'type' => 'datetime', 'align' => 'right'),

#
#----------[ FIND ]----------
#
public function viewstock_mvt()
 {
  global $cookie;

#
#----------[ REPLACE WITH ]----------
#
public function viewstock_mvt()
 {
  global $currentIndex, $cookie;

#
#----------[ FIND ]----------
#
echo '</table>';
 }
 
 public function display()

#
#----------[ REPLACE WITH ]----------
#
echo '</table>';
   echo '<div class="clear" style="height:20px;">&nbsp;</div>
   <br /><br /><a href="'.$currentIndex.'&token='.$this->token.'"><img src="../img/admin/arrow2.gif" /> '.$this->l('Back to list').'</a><br />';
 }
 
 public function display()

Back Link for Carts Tab v1.0

Add a "Back to list" link on the bottom of the cart detail page.
#
#----------[ OPEN ]----------
#
admin/tabs/AdminCarts.php

#
#----------[ FIND ]----------
#
    // Cancel product
    echo '
   </fieldset>
  <div class="clear" style="height:20px;">&nbsp;</div>';

#
#----------[ AFTER, ADD ]----------
#
  echo '<br /><br /><a href="'.$currentIndex.'&token='.$this->token.'"><img src="../img/admin/arrow2.gif" alt="" /> '.$this->l('Back to cart list').'</a><br />';

25 November 2011

Enhanced Product Details Statistics Module v1.0

Adds a table of sold attributes grouped by quantity to the BO product details statistics module.
#  
#----------[ OPEN ]----------  
#  
modules\statsproduct\statsproduct.php  
   
#  
#----------[ FIND ]----------  
#  
      public function hookAdminStatsModules($params)  
   
#  
#----------[ BEFORE, ADD ]----------  
#  
      private function getBestAttributes($id_product)  
      {  
           return Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('  
           SELECT od.product_name, SUM(od.product_quantity) as pqty  
           FROM `'._DB_PREFIX_.'orders` o  
           LEFT JOIN `'._DB_PREFIX_.'order_detail` od ON o.id_order = od.id_order  
           WHERE o.date_add BETWEEN '.$this->getDate().'   
           AND o.valid = 1  
           AND od.product_id = '.(int)($id_product).'  
           GROUP BY od.product_attribute_id  
           ORDER BY pqty DESC');  
      }  
   
#  
#----------[ FIND ]----------  
#  
                     $this->_html .= '<h3 class="space">'.$this->l('Attribute sales distribution').'</h3><center>'.ModuleGraph::engine(array('type' => 'pie', 'option' => '3-'.$id_product)).'</center><br />  
                <p><a href="'.Tools::safeOutput($_SERVER['REQUEST_URI']).'&export=1&exportType=2"><img src="../img/admin/asterisk.gif" />'.$this->l('CSV Export').'</a></p><br />';  
   
#  
#----------[ REPLACE WITH ]----------  
#  
                {  
                     $this->_html .= '<h3 class="space">'.$this->l('Attribute sales distribution').'</h3><center>'.ModuleGraph::engine(array('type' => 'pie', 'option' => '3-'.$id_product)).'</center><br />  
                    <p><a href="'.Tools::safeOutput($_SERVER['REQUEST_URI']).'&export=1&exportType=2"><img src="../img/admin/asterisk.gif" />'.$this->l('CSV Export').'</a></p><br />';  
                     $top_attributes = $this->getBestAttributes($id_product);  
                     $this->_html .= '<br class="clear" />  
                     <h3>'.$this->l('Best attribute sales').'</h3>  
                     <div style="overflow-y: scroll; height: '.min(200, (count($top_attributes)+1)*32).'px;">  
                     <table class="table" border="0" cellspacing="0" cellspacing="0">  
                     <thead>  
                          <tr>  
                               <th>'.$this->l('Attribute').'</th>  
                               <th>'.$this->l('Qty').'</th>  
                          </tr>  
                     </thead><tbody>';       
                     foreach ($top_attributes as $attribute)  
                          $this->_html .= '  
                          <tr>  
                               <td>'.$attribute['product_name'].'</td>  
                               <td align="right">'.(int)($attribute['pqty']).'</td>  
                          </tr>';                                     
                     $this->_html .= '</tbody></table></div>';  
                }

18 November 2011

Link Product Accessories to Product Page v1.0

Slight improvement to link a product accessory to it's product page in BO. Very useful to check if the accessory is linked back to the main product.
#  
#----------[ OPEN ]----------  
#  
admin/tabs/AdminProduct.php

#  
#----------[ FIND ]----------  
#  
echo htmlentities($accessory['name'], ENT_COMPAT, 'UTF-8').(!empty($accessory['reference']) ? ' ('.$accessory['reference'].')' : '').' <span onclick="delAccessory('.$accessory['id_product'].');" style="cursor: pointer;"><img src="../img/admin/delete.gif" class="middle" alt="" /></span><br />';

#  
#----------[ REPLACE WITH ]----------  
#  
echo '<a href="index.php?tab=AdminCatalog&id_product='.$accessory['id_product'].'&updateproduct&token='.$this->token.'">'.htmlentities($accessory['name'], ENT_COMPAT, 'UTF-8').(!empty($accessory['reference']) ? ' ('.$accessory['reference'].')' : '').'</a> <span onclick="delAccessory('.$accessory['id_product'].');" style="cursor: pointer;"><img src="../img/admin/delete.gif" class="middle" alt="" /></span><br />';