// Improved Pack management
This commit is contained in:
@@ -45,6 +45,8 @@
|
||||
<p>{l s='You can choose to use the advanced stock management system for this product or not.'}</p>
|
||||
<p>{l s='You can manually specify the quantities for the product / each product combinations, or choose to automatically determine these quantities based on your stock (if advanced stock management is activated).'}</p>
|
||||
<p>{l s='In this case, the quantities correspond to the quantitites of the real stock in the warehouses associated to the current shop or current group of shops.'}</p>
|
||||
<br/>
|
||||
<p>{l s='For packs, if it has products that use the advanced stock management, you have to specify a common warehouse for these products and the pack.'}</p>
|
||||
</div>
|
||||
<br />
|
||||
<h4>{l s='Available quantities for sale'}</h4>
|
||||
@@ -72,8 +74,10 @@
|
||||
type="checkbox" name="advanced_stock_management" class="advanced_stock_management" id="advanced_stock_management" />
|
||||
<label style="float:none;font-weight:normal" for="advanced_stock_management">
|
||||
{l s='I want to use the advanced stock management system for this product'}
|
||||
{if $stock_management_active == 0}
|
||||
{if $stock_management_active == 0 && !$product->cache_is_pack}
|
||||
- <b>{l s='This requires to enable the advanced stock management.'}</b>
|
||||
{else if $product->cache_is_pack}
|
||||
- <b>{l s='This parameter depends on the product(s) in the pack.'}</b>
|
||||
{/if}
|
||||
</label>
|
||||
<br /><br />
|
||||
@@ -91,8 +95,10 @@
|
||||
type="radio" name="depends_on_stock" class="depends_on_stock" id="depends_on_stock_1" value="1"/>
|
||||
<label style="float:none;font-weight:normal" for="depends_on_stock_1">
|
||||
{l s='Available quantities for current product and its combinations are based on stock in the warehouses'}
|
||||
{if $stock_management_active == 0 || $product->advanced_stock_management == 0}
|
||||
{if ($stock_management_active == 0 || $product->advanced_stock_management == 0) && !$product->cache_is_pack}
|
||||
- <b>{l s='This requires to enable the advanced stock management globaly/for this product.'}</b>
|
||||
{else if $product->cache_is_pack}
|
||||
- <b>{l s='This parameter depends on the product(s) in the pack.'}</b>
|
||||
{/if}
|
||||
</label>
|
||||
<br /><br />
|
||||
|
||||
+17
-13
@@ -739,7 +739,7 @@ class CartCore extends ObjectModel
|
||||
{
|
||||
if (!$shop)
|
||||
$shop = Context::getContext()->shop;
|
||||
|
||||
|
||||
if (Context::getContext()->customer->id)
|
||||
{
|
||||
if ($id_address_delivery == 0) // The $id_address_delivery is null, get the default customer address
|
||||
@@ -1388,13 +1388,15 @@ class CartCore extends ObjectModel
|
||||
|
||||
$product['warehouse_list'] = array();
|
||||
|
||||
if ($stock_management_active && (int)$product['advanced_stock_management'] == 1)
|
||||
if ($stock_management_active &&
|
||||
((int)$product['advanced_stock_management'] == 1 || Pack::usesAdvancedStockManagement((int)$product['id_product'])))
|
||||
{
|
||||
$warehouse_list = Warehouse::getProductWarehouseList($product['id_product'], $product['id_product_attribute'], $this->id_shop);
|
||||
if (count($warehouse_list) == 0)
|
||||
$warehouse_list = Warehouse::getProductWarehouseList($product['id_product'], $product['id_product_attribute']);
|
||||
// Does the product is in stock ?
|
||||
// If yes, get only warehouse where the product is in stock
|
||||
|
||||
$warehouse_in_stock = array();
|
||||
$manager = StockManagerFactory::getManager();
|
||||
|
||||
@@ -1407,7 +1409,7 @@ class CartCore extends ObjectModel
|
||||
true
|
||||
);
|
||||
|
||||
if ($product_real_quantities > 0)
|
||||
if ($product_real_quantities > 0 || Pack::isPack((int)$product['id_product']))
|
||||
$warehouse_in_stock[] = $warehouse;
|
||||
}
|
||||
|
||||
@@ -1459,9 +1461,9 @@ class CartCore extends ObjectModel
|
||||
foreach ($warehouse_count_by_address[$product['id_address_delivery']] as $id_warehouse => $val)
|
||||
if (in_array((int)$id_warehouse, $product['warehouse_list']))
|
||||
break;
|
||||
|
||||
|
||||
$id_warehouse = (int)$id_warehouse;
|
||||
|
||||
|
||||
if (!isset($grouped_by_warehouse[$product['id_address_delivery']]['in_stock'][$id_warehouse]))
|
||||
{
|
||||
$grouped_by_warehouse[$product['id_address_delivery']]['in_stock'][$id_warehouse] = array();
|
||||
@@ -1575,7 +1577,7 @@ class CartCore extends ObjectModel
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5 : Reduce deep of $package_list
|
||||
// Step 5 : Reduce depth of $package_list
|
||||
$final_package_list = array();
|
||||
foreach ($package_list as $id_address_delivery => $products_in_stock_list)
|
||||
{
|
||||
@@ -1585,11 +1587,13 @@ class CartCore extends ObjectModel
|
||||
foreach ($products_in_stock_list as $key => $warehouse_list)
|
||||
foreach ($warehouse_list as $id_warehouse => $products_grouped_by_carriers)
|
||||
foreach ($products_grouped_by_carriers as $data)
|
||||
{
|
||||
$final_package_list[$id_address_delivery][] = array(
|
||||
'product_list' => $data['product_list'],
|
||||
'carrier_list' => $data['carrier_list'],
|
||||
'id_warehouse' => $id_warehouse,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$cache = $final_package_list;
|
||||
@@ -1951,7 +1955,7 @@ class CartCore extends ObjectModel
|
||||
}
|
||||
|
||||
$delivery_option_list = $this->getDeliveryOptionList(null , true);
|
||||
|
||||
|
||||
foreach ($delivery_option_list as $id_address => $options)
|
||||
if (!isset($delivery_option[$id_address]))
|
||||
foreach ($options as $key => $option)
|
||||
@@ -2895,9 +2899,9 @@ class CartCore extends ObjectModel
|
||||
$sql->where('id_address_delivery = '.(int)$id_address_delivery);
|
||||
$sql->where('id_cart = '.(int)$this->id);
|
||||
$duplicatedQuantity = Db::getInstance()->getValue($sql);
|
||||
|
||||
|
||||
if ($duplicatedQuantity > $quantity) {
|
||||
|
||||
|
||||
$sql = 'UPDATE '._DB_PREFIX_.'cart_product
|
||||
SET `quantity` = `quantity` - '.(int)$quantity.'
|
||||
WHERE id_cart = '.(int)$this->id.'
|
||||
@@ -2955,7 +2959,7 @@ class CartCore extends ObjectModel
|
||||
AND id_address_delivery = '.(int)$new_id_address_delivery;
|
||||
Db::getInstance()->execute($sql);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3032,10 +3036,10 @@ class CartCore extends ObjectModel
|
||||
$id_address_delivery = (int)$this->id_address_delivery;
|
||||
else
|
||||
$id_address_delivery = (int)Address::getFirstCustomerAddressId(Context::getContext()->customer->id);
|
||||
|
||||
|
||||
if (!$id_address_delivery)
|
||||
return;
|
||||
|
||||
|
||||
// Update
|
||||
$sql = 'UPDATE `'._DB_PREFIX_.'cart_product`
|
||||
SET `id_address_delivery` = '.(int)$id_address_delivery.'
|
||||
@@ -3048,7 +3052,7 @@ class CartCore extends ObjectModel
|
||||
SET `id_address_delivery` = '.(int)$id_address_delivery.'
|
||||
WHERE `id_cart` = '.(int)$this->id.'
|
||||
AND (`id_address_delivery` = 0 OR `id_address_delivery` IS NULL)';
|
||||
|
||||
|
||||
Db::getInstance()->execute($sql);
|
||||
}
|
||||
|
||||
|
||||
@@ -228,5 +228,27 @@ class PackCore extends Product
|
||||
FROM `'._DB_PREFIX_.'pack`
|
||||
');
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given pack, tells if it has at least one product using the advanced stock management
|
||||
*
|
||||
* @param int $id_product id_pack
|
||||
* @return bool
|
||||
*/
|
||||
public static function usesAdvancedStockManagement($id_product)
|
||||
{
|
||||
if (!Pack::isPack($id_product))
|
||||
return false;
|
||||
|
||||
$products = self::getItems($id_product, Configuration::get('PS_LANG_DEFAULT'));
|
||||
foreach ($products as $product)
|
||||
{
|
||||
// if one product uses the advanced stock management
|
||||
if ($product->advanced_stock_management == 1)
|
||||
return true;
|
||||
}
|
||||
// not used
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,8 +95,6 @@ class OrderHistoryCore extends ObjectModel
|
||||
&& $oldOrderStatus->logable))
|
||||
{
|
||||
ProductSale::addProductSale($product['product_id'], $product['product_quantity']);
|
||||
if ($oldOrderStatus->id == Configuration::get('PS_OS_ERROR') || $oldOrderStatus->id == Configuration::get('PS_OS_CANCELED'))
|
||||
StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], -(int)$product['product_quantity'], $order->id_shop);
|
||||
}
|
||||
/* If becoming unlogable => removing sale */
|
||||
else if (!$newOS->logable
|
||||
@@ -124,7 +122,7 @@ class OrderHistoryCore extends ObjectModel
|
||||
&& $oldOrderStatus instanceof OrderState
|
||||
&& $oldOrderStatus->shipped == 0
|
||||
&& Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')
|
||||
&& (int)$product['advanced_stock_management'] == 1)
|
||||
&& ((int)$product['advanced_stock_management'] == 1 || Pack::usesAdvancedStockManagement($product['product_id'])))
|
||||
{
|
||||
$manager = StockManagerFactory::getManager();
|
||||
$warehouse = new Warehouse($product['id_warehouse']);
|
||||
@@ -143,27 +141,54 @@ class OrderHistoryCore extends ObjectModel
|
||||
StockAvailable::synchronize($product['product_id']);
|
||||
else
|
||||
StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], -(int)$product['product_quantity'], $order->id_shop);
|
||||
//@TODO Synchronize for products in pack if needed ?!
|
||||
}
|
||||
else if ($newOS->shipped == 0
|
||||
&& $oldOrderStatus instanceof OrderState
|
||||
&& $oldOrderStatus->shipped == 1
|
||||
&& Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')
|
||||
&& (int)$product['advanced_stock_management'] == 1
|
||||
)
|
||||
&& ((int)$product['advanced_stock_management'] == 1 || Pack::usesAdvancedStockManagement($product['product_id'])))
|
||||
{
|
||||
$manager = StockManagerFactory::getManager();
|
||||
$mvts = StockMvt::getNegativeStockMvts($order->id, $product['product_id'], $product['product_attribute_id'], $product['product_quantity']);
|
||||
foreach ($mvts as $mvt)
|
||||
if (Pack::isPack($product['product_id']))
|
||||
{
|
||||
$manager->addProduct(
|
||||
$product['product_id'],
|
||||
$product['product_attribute_id'],
|
||||
new Warehouse($mvt['id_warehouse']),
|
||||
$mvt['physical_quantity'],
|
||||
null,
|
||||
$mvt['price_te'],
|
||||
true
|
||||
);
|
||||
$pack_products = Pack::getItems($product['product_id'], Configuration::get('PS_LANG_DEFAULT'));
|
||||
foreach ($pack_products as $pack_product)
|
||||
{
|
||||
if ($pack_product->advanced_stock_management == 1)
|
||||
{
|
||||
$mvts = StockMvt::getNegativeStockMvts($order->id, $pack_product->id, 0, $pack_product->pack_quantity * $product['product_quantity']);
|
||||
foreach ($mvts as $mvt)
|
||||
{
|
||||
$manager->addProduct(
|
||||
$pack_product->id,
|
||||
0,
|
||||
new Warehouse($mvt['id_warehouse']),
|
||||
$mvt['physical_quantity'],
|
||||
null,
|
||||
$mvt['price_te'],
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
$mvts = StockMvt::getNegativeStockMvts($order->id, $product['product_id'], $product['product_attribute_id'], $product['product_quantity']);
|
||||
foreach ($mvts as $mvt)
|
||||
{
|
||||
$manager->addProduct(
|
||||
$product['product_id'],
|
||||
$product['product_attribute_id'],
|
||||
new Warehouse($mvt['id_warehouse']),
|
||||
$mvt['physical_quantity'],
|
||||
null,
|
||||
$mvt['price_te'],
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (StockAvailable::dependsOnStock($product['product_id'], $order->id_shop))
|
||||
|
||||
@@ -207,12 +207,14 @@ class StockManagerCore implements StockManagerInterface
|
||||
// Special case of a pack
|
||||
if (Pack::isPack($id_product))
|
||||
{
|
||||
// Gets items
|
||||
$products_pack = Pack::getItems($id_product, (int)Configuration::get('PS_LANG_DEFAULT'));
|
||||
// Foreach item
|
||||
foreach ($products_pack as $product_pack)
|
||||
{
|
||||
//@TODO is there a better way to retrieve the product attribute assciated to the pack ?
|
||||
$pack_id_product_attribute = Product::getDefaultAttribute($id_product_attribute, 1);
|
||||
$this->removeProduct($product_pack->id, $pack_id_product_attribute, $product_pack->pack_quantity * $quantity, $warehouse, $id_order);
|
||||
//TODO $pack_id_product_attribute = Product::getDefaultAttribute($id_product_attribute, 1);
|
||||
if ($product_pack->advanced_stock_management == 1)
|
||||
$this->removeProduct($product_pack->id, 0, $warehouse, $product_pack->pack_quantity * $quantity, $id_stock_mvt_reason, $is_usable, $id_order);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -633,4 +635,5 @@ class StockManagerCore implements StockManagerInterface
|
||||
|
||||
return $stocks;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -309,6 +309,16 @@ class WarehouseCore extends ObjectModel
|
||||
if (is_null($id_shop))
|
||||
$id_shop = Context::getContext()->shop->getID(true);
|
||||
|
||||
// if it's a pack, returns warehouses if and only if some products use the advanced stock management
|
||||
if (Pack::isPack($id_product))
|
||||
{
|
||||
$warehouses = self::getPackWarehouses($id_product);
|
||||
$res = array();
|
||||
foreach ($warehouses as $warehouse)
|
||||
$res[]['id_warehouse'] = $warehouse;
|
||||
return $res;
|
||||
}
|
||||
|
||||
$query = new DbQuery();
|
||||
$query->select('wpl.id_warehouse, CONCAT(w.reference, " - ", w.name) as name');
|
||||
$query->from('warehouse_product_location', 'wpl');
|
||||
@@ -475,6 +485,50 @@ class WarehouseCore extends ObjectModel
|
||||
return Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given pack, returns the warehouse it can be shipped from
|
||||
*
|
||||
* @param int $id_product
|
||||
* @return int|bool id_warehouse or false
|
||||
*/
|
||||
public static function getPackWarehouses($id_product, $id_shop = null)
|
||||
{
|
||||
if (!Pack::isPack($id_product))
|
||||
return false;
|
||||
|
||||
if (is_null($id_shop))
|
||||
$id_shop = Context::getContext()->shop->getID(true);
|
||||
|
||||
// warehouses of the pack
|
||||
$pack_warehouses = WarehouseProductLocation::getCollection((int)$id_product);
|
||||
// products in the pack
|
||||
$products = Pack::getItems((int)$id_product, Configuration::get('PS_LANG_DEFAULT'));
|
||||
|
||||
// array with all warehouses id to check
|
||||
$list = array();
|
||||
|
||||
// fills $list
|
||||
foreach ($pack_warehouses as $pack_warehouse)
|
||||
$list['pack_warehouses'][] = (int)$pack_warehouse->id_warehouse;
|
||||
|
||||
// for each products in the pack
|
||||
foreach ($products as $product)
|
||||
{
|
||||
if ($product->advanced_stock_management)
|
||||
{
|
||||
// gets the warehouses of one product
|
||||
$product_warehouses = Warehouse::getProductWarehouseList((int)$product->id, 0, (int)$id_shop);
|
||||
$list[(int)$product->id] = array();
|
||||
// fills array with warehouses for this product
|
||||
foreach ($product_warehouses as $product_warehouse)
|
||||
$list[(int)$product->id][] = $product_warehouse['id_warehouse'];
|
||||
}
|
||||
}
|
||||
|
||||
// returns final list
|
||||
return call_user_func_array('array_intersect', $list);
|
||||
}
|
||||
|
||||
/*********************************\
|
||||
*
|
||||
* Webservices Specific Methods
|
||||
|
||||
@@ -129,7 +129,7 @@ class WarehouseProductLocationCore extends ObjectModel
|
||||
public static function getCollection($id_product)
|
||||
{
|
||||
$collection = new Collection('WarehouseProductLocation');
|
||||
$collection->where('id_product', '=', $id_product);
|
||||
$collection->where('id_product', '=', (int)$id_product);
|
||||
return $collection;
|
||||
}
|
||||
}
|
||||
@@ -3499,7 +3499,8 @@ class AdminProductsControllerCore extends AdminController
|
||||
$show_quantities = false;
|
||||
}
|
||||
// if we are in shop context
|
||||
else {
|
||||
else
|
||||
{
|
||||
// if quantities are shared between shops of the group, it's not possible to manage them for a given shop
|
||||
if ($group_shop->share_stock)
|
||||
$show_quantities = false;
|
||||
@@ -3549,8 +3550,10 @@ class AdminProductsControllerCore extends AdminController
|
||||
// gets an array of quantities (quantity for the product / quantity in pack)
|
||||
$pack_quantities = array();
|
||||
foreach ($items as $item)
|
||||
{
|
||||
if (!$item->isAvailableWhenOutOfStock((int)$item->out_of_stock))
|
||||
$pack_quantities[] = Product::getQuantity($item->id) / ($item->pack_quantity !== 0 ? $item->pack_quantity : 1);
|
||||
}
|
||||
|
||||
// gets the minimum
|
||||
$pack_quantity = $pack_quantities[0];
|
||||
@@ -3559,6 +3562,9 @@ class AdminProductsControllerCore extends AdminController
|
||||
if ($pack_quantity > $value)
|
||||
$pack_quantity = $value;
|
||||
}
|
||||
|
||||
if (!Warehouse::getPackWarehouses((int)$obj->id))
|
||||
$this->displayWarning($this->l('You have to have a common warehouse between this pack and its products because .'));
|
||||
}
|
||||
|
||||
$data->assign(array(
|
||||
|
||||
Reference in New Issue
Block a user