// Updated OrderHistory / StockManager. Added feature to StockCover: it is now possible to display the number of sales per product / and highlight products which coverage is less than a given threshold
This commit is contained in:
@@ -222,7 +222,7 @@ form#product_form h4 { font-size:18px; font-weight:normal;}
|
||||
.filter-module .button-filter { float:right;}
|
||||
|
||||
/*FILTER STOCK*/
|
||||
.filter-stock { background-color:#ebedf4; border:1px solid #c2c4d9; margin-bottom:15px; padding:10px; display:block; min-height:25px;}
|
||||
.filter-stock { background-color:#ebedf4; border:1px solid #c2c4d9; margin-bottom:15px; padding:10px; display:block; min-height:65px;}
|
||||
.filter-stock #stock_cover {float:left; margin-right:30px;}
|
||||
.filter-stock #stock_instant_state {float:left; margin-right:30px;}
|
||||
.filter-stock #supply_orders {float:left; margin-right:30px;}
|
||||
|
||||
@@ -55,6 +55,10 @@ $(document).ready(function() {
|
||||
.attr('colspan', $('#details_{$id}').parent().parent().find('td').length)));
|
||||
$.each(data.data, function(it, row)
|
||||
{
|
||||
var bg_color = ''; // Color
|
||||
if (row.color)
|
||||
bg_color = 'style="background:' + row.color +';"';
|
||||
|
||||
var content = $('<tr class="action_details details_{$id} '+(alt_row ? 'alt_row' : '')+'"></tr>');
|
||||
content.append($('<td class="empty"></td>'));
|
||||
var first = true;
|
||||
@@ -69,9 +73,9 @@ $(document).ready(function() {
|
||||
if (typeof(row[it]) == 'undefined')
|
||||
{
|
||||
if (first || count == 0)
|
||||
content.append($('<td class="'+this.align+' empty"></td>'));
|
||||
content.append($('<td class="'+this.align+' empty"' + bg_color + '></td>'));
|
||||
else
|
||||
content.append($('<td class="'+this.align+'"></td>'));
|
||||
content.append($('<td class="'+this.align+'"' + bg_color + '></td>'));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -79,12 +83,12 @@ $(document).ready(function() {
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
content.append($('<td class="'+this.align+' first">'+row[it]+'</td>'));
|
||||
content.append($('<td class="'+this.align+' first"' + bg_color + '>'+row[it]+'</td>'));
|
||||
}
|
||||
else if (count == 0)
|
||||
content.append($('<td class="'+this.align+' last">'+row[it]+'</td>'));
|
||||
content.append($('<td class="'+this.align+' last"' + bg_color + '>'+row[it]+'</td>'));
|
||||
else
|
||||
content.append($('<td class="'+this.align+' '+count+'">'+row[it]+'</td>'));
|
||||
content.append($('<td class="'+this.align+' '+count+'"' + bg_color + '>'+row[it]+'</td>'));
|
||||
}
|
||||
});
|
||||
content.append($('<td class="empty"></td>'));
|
||||
|
||||
@@ -30,20 +30,31 @@
|
||||
<input type="hidden" name="controller" value="AdminStockCover" />
|
||||
<input type="hidden" name="token" value="{$token}" />
|
||||
{if count($stock_cover_periods) > 1}
|
||||
<label for="coverage_period">{l s='Filter by period/warehouse:'}</label>
|
||||
<select name="coverage_period" onChange="$(this).parent().submit();">
|
||||
<div>
|
||||
<label for="coverage_period">{l s='Filter by period:'}</label>
|
||||
<select name="coverage_period" onChange="$(this).parent().parent().submit();">
|
||||
{foreach from=$stock_cover_periods key=k item=i}
|
||||
<option {if $i == $stock_cover_cur_period} selected="selected"{/if} value="{$i}">{$k}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
{/if}
|
||||
{if count($stock_cover_warehouses) > 0}
|
||||
<select name="id_warehouse" onChange="$(this).parent().submit();">
|
||||
<div>
|
||||
<label for="id_warehouse">{l s='Filter by warehouse:'}</label>
|
||||
<select name="id_warehouse" onChange="$(this).parent().parent().submit();"">
|
||||
{foreach from=$stock_cover_warehouses key=k item=i}
|
||||
<option {if $i.id_warehouse == $stock_cover_cur_warehouse} selected="selected"{/if} value="{$i.id_warehouse}">{$i.name}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
{/if}
|
||||
<div>
|
||||
<label for="warn_days">{l s='Highlight when coverage is less than:'}</label>
|
||||
<input name="warn_days" type="text" size="3" onChange="$(this).parent().parent().submit();"
|
||||
value="{if isset($stock_cover_warn_days)}{$stock_cover_warn_days}{/if}">
|
||||
</input>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
@@ -30,13 +30,18 @@
|
||||
<form id="supply_orders" type="get">
|
||||
<input type="hidden" name="controller" value="AdminSupplyOrders" />
|
||||
<input type="hidden" name="token" value="{$token}" />
|
||||
<label for="filter_status">{l s='Choose not to display completed/canceled orders and filter by warehouse:'}</label>
|
||||
<input type="checkbox" name="filter_status" class="noborder" onChange="$(this).parent().submit();" {if $filter_status == 1}value="on" checked{/if}></input>
|
||||
<select name="id_warehouse" onChange="$(this).parent().submit();">
|
||||
<div>
|
||||
<label for="id_warehouse">{l s='Filter by warehouse:'}</label>
|
||||
<select name="id_warehouse" onChange="$(this).parent().parent().submit();">
|
||||
{foreach from=$warehouses key=k item=i}
|
||||
<option {if $i.id_warehouse == $current_warehouse} selected="selected"{/if} value="{$i.id_warehouse}">{$i.name}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</select>
|
||||
</div>
|
||||
<div style="margin-top: 5px;">
|
||||
<label for="filter_status">{l s='Choose not to display completed/canceled orders:'}</label>
|
||||
<input type="checkbox" name="filter_status" class="noborder" onChange="$(this).parent().parent().submit();" {if $filter_status == 1}value="on" checked{/if}></input>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -127,6 +127,11 @@ class OrderHistoryCore extends ObjectModel
|
||||
true,
|
||||
(int)$id_order
|
||||
);
|
||||
|
||||
if (StockAvailable::dependsOnStock($product['id_product'], $order->id_shop))
|
||||
StockAvailable::synchronize($product['id_product']);
|
||||
else
|
||||
StockAvailable::updateQuantity($product['id_product'], $product['id_product_attribute'], -(int)$product['cart_quantity'], $order->id_shop);
|
||||
}
|
||||
else if ($newOS->shipped == 0 && $oldOrderStatus->shipped == 1 && Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT'))
|
||||
{
|
||||
|
||||
@@ -554,7 +554,7 @@ class StockManagerCore implements StockManagerInterface
|
||||
/**
|
||||
* @see StockManagerInterface::getProductCoverage()
|
||||
* Here, $coverage is a number of days
|
||||
* @return int number of days left
|
||||
* @return int number of days left (-1 if infinite)
|
||||
*/
|
||||
public function getProductCoverage($id_product, $id_product_attribute, $coverage, $id_warehouse = null)
|
||||
{
|
||||
@@ -584,14 +584,14 @@ class StockManagerCore implements StockManagerInterface
|
||||
|
||||
$quantity_out = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
|
||||
if (!$quantity_out)
|
||||
return '--';
|
||||
return -1;
|
||||
|
||||
$quantity_per_day = round($quantity_out / $coverage);
|
||||
$quantity_per_day = Tools::ps_round($quantity_out / $coverage);
|
||||
$physical_quantity = $this->getProductPhysicalQuantities($id_product,
|
||||
$id_product_attribute,
|
||||
($id_warehouse ? array($id_warehouse) : null),
|
||||
true);
|
||||
$time_left = ($quantity_per_day == 0) ? '--' : round($physical_quantity / $quantity_per_day);
|
||||
$time_left = ($quantity_per_day == 0) ? (-1) : Tools::ps_round($physical_quantity / $quantity_per_day);
|
||||
|
||||
return $time_left;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ class AdminStockCoverControllerCore extends AdminController
|
||||
$this->table = 'product';
|
||||
$this->className = 'Product';
|
||||
$this->lang = true;
|
||||
$this->colorOnBackground = true;
|
||||
|
||||
$this->fieldsDisplay = array(
|
||||
'reference' => array(
|
||||
@@ -63,12 +64,19 @@ class AdminStockCoverControllerCore extends AdminController
|
||||
'title' => $this->l('Name'),
|
||||
'filter_key' => 'b!name'
|
||||
),
|
||||
'qty_sold' => array(
|
||||
'title' => $this->l('Quantity sold'),
|
||||
'width' => 160,
|
||||
'orderby' => false,
|
||||
'search' => false,
|
||||
'hint' => $this->l('Quantity sold during the defined period.'),
|
||||
),
|
||||
'coverage' => array(
|
||||
'title' => $this->l('Coverage'),
|
||||
'width' => 160,
|
||||
'orderby' => false,
|
||||
'search' => false,
|
||||
'hint' => $this->l('Days left before you run out of stock.')
|
||||
'hint' => $this->l('Days left before you run out of stock.'),
|
||||
),
|
||||
'stock' => array(
|
||||
'title' => $this->l('Quantity'),
|
||||
@@ -135,11 +143,25 @@ class AdminStockCoverControllerCore extends AdminController
|
||||
{
|
||||
$data['name'] = Product::getProductName($data['id_product'], $data['id']);
|
||||
|
||||
if ($this->getCurrentCoverageWarehouse() == -1)
|
||||
$data['coverage'] = StockManagerFactory::getManager()->getProductCoverage($data['id_product'], $data['id'], $period);
|
||||
else
|
||||
$data['coverage'] = StockManagerFactory::getManager()->getProductCoverage($data['id_product'], $data['id'], $period, $warehouse);
|
||||
// computes coverage
|
||||
$coverage = StockManagerFactory::getManager()->getProductCoverage(
|
||||
$data['id_product'],
|
||||
$data['id'],
|
||||
$period,
|
||||
(($this->getCurrentCoverageWarehouse() == -1) ? null : $warehouse)
|
||||
);
|
||||
if ($coverage != -1) // if coverage is available
|
||||
{
|
||||
if ($coverage < $this->getCurrentWarning()) // if highlight needed
|
||||
$data['color'] = '#BDE5F8';
|
||||
$data['coverage'] = $coverage;
|
||||
}
|
||||
else // infinity
|
||||
$data['coverage'] = '--';
|
||||
|
||||
$data['qty_sold'] = $this->getQuantitySold($data['id_product'], $data['id'], $this->getCurrentCoveragePeriod());
|
||||
}
|
||||
|
||||
echo Tools::jsonEncode(array('data'=> $datas, 'fields_display' => $this->fieldsDisplay));
|
||||
}
|
||||
die;
|
||||
@@ -169,7 +191,12 @@ class AdminStockCoverControllerCore extends AdminController
|
||||
$this->tpl_list_vars['stock_cover_cur_period'] = $this->getCurrentCoveragePeriod();
|
||||
$this->tpl_list_vars['stock_cover_warehouses'] = $this->stock_cover_warehouses;
|
||||
$this->tpl_list_vars['stock_cover_cur_warehouse'] = $this->getCurrentCoverageWarehouse();
|
||||
$this->ajax_params = array('period' => $this->getCurrentCoveragePeriod(), 'id_warehouse' => $this->getCurrentCoverageWarehouse());
|
||||
$this->tpl_list_vars['stock_cover_warn_days'] = $this->getCurrentWarning();
|
||||
$this->ajax_params = array(
|
||||
'period' => $this->getCurrentCoveragePeriod(),
|
||||
'id_warehouse' => $this->getCurrentCoverageWarehouse(),
|
||||
'warn_days' => $this->getCurrentWarning()
|
||||
);
|
||||
|
||||
$this->displayInformation($this->l('Considering the coverage period choosen and the quantity of products/combinations that you sold,
|
||||
this interface gives you an idea of when one product will run out of stock.'));
|
||||
@@ -191,22 +218,30 @@ class AdminStockCoverControllerCore extends AdminController
|
||||
$item = &$this->_list[$i];
|
||||
if ((int)$item['variations'] <= 0)
|
||||
{
|
||||
if ($this->getCurrentCoverageWarehouse() == -1) // if all warehouses
|
||||
$item['coverage'] = StockManagerFactory::getManager()->getProductCoverage(
|
||||
$item['id'],
|
||||
0,
|
||||
$this->getCurrentCoveragePeriod()
|
||||
);
|
||||
else // else selected warehouse
|
||||
$item['coverage'] = StockManagerFactory::getManager()->getProductCoverage(
|
||||
$item['id'],
|
||||
0,
|
||||
$this->getCurrentCoveragePeriod(),
|
||||
$this->getCurrentCoverageWarehouse()
|
||||
);
|
||||
// computes coverage and displays (highlights if needed)
|
||||
$coverage = StockManagerFactory::getManager()->getProductCoverage(
|
||||
$item['id'],
|
||||
0,
|
||||
$this->getCurrentCoveragePeriod(),
|
||||
(($this->getCurrentCoverageWarehouse() == -1) ? null : $this->getCurrentCoverageWarehouse())
|
||||
);
|
||||
if ($coverage != -1) // coverage is available
|
||||
{
|
||||
if ($coverage < $this->getCurrentWarning())
|
||||
$item['color'] = '#BDE5F8';
|
||||
|
||||
$item['coverage'] = $coverage;
|
||||
}
|
||||
else // infinity
|
||||
$item['coverage'] = '--';
|
||||
|
||||
// computes quantity sold
|
||||
$item['qty_sold'] = $this->getQuantitySold($item['id'], 0, $this->getCurrentCoveragePeriod());
|
||||
|
||||
// removes 'details' action on products without attributes
|
||||
$this->addRowActionSkipList('details', array($item['id']));
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -253,4 +288,40 @@ class AdminStockCoverControllerCore extends AdminController
|
||||
}
|
||||
return $warehouse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current warning
|
||||
*
|
||||
* @return int warn period
|
||||
*/
|
||||
private function getCurrentWarning()
|
||||
{
|
||||
static $warning = 0;
|
||||
|
||||
if ($warning == 0)
|
||||
{
|
||||
$warning = 0;
|
||||
if (Tools::getValue('warn_days') && Validate::isInt(Tools::getValue('warn_days')))
|
||||
$warning = (int)Tools::getValue('warn_days');
|
||||
}
|
||||
return $warning;
|
||||
}
|
||||
|
||||
protected function getQuantitySold($id_product, $id_product_attribute, $coverage)
|
||||
{
|
||||
$query = new DbQuery();
|
||||
$query->select('SUM(od.product_quantity)');
|
||||
$query->from('order_detail od');
|
||||
$query->leftJoin('orders o ON (od.id_order = o.id_order)');
|
||||
$query->leftJoin('order_history oh ON (o.date_upd = oh.date_add)');
|
||||
$query->leftJoin('order_state os ON (os.id_order_state = oh.id_order_state)');
|
||||
$query->where('od.product_id = '.(int)$id_product);
|
||||
$query->where('od.product_attribute_id = '.(int)$id_product_attribute);
|
||||
$query->where('TO_DAYS(NOW()) - TO_DAYS(oh.date_add) <= '.(int)$coverage);
|
||||
$query->where('o.valid = 1');
|
||||
$query->where('os.logable = 1 AND os.delivery = 1 AND os.shipped = 1');
|
||||
|
||||
$quantity = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
|
||||
return $quantity;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user