diff --git a/controllers/StockController.php b/controllers/StockController.php
index 3cbcd174..f704c84e 100644
--- a/controllers/StockController.php
+++ b/controllers/StockController.php
@@ -16,7 +16,7 @@ class StockController extends BaseController
$nextXDays = $usersService->GetUserSettings(GROCY_USER_ID)['stock_expring_soon_days'];
return $this->renderPage($response, 'stockoverview', [
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
'locations' => $this->getDatabase()->locations()->orderBy('name'),
'currentStock' => $this->getStockService()->GetCurrentStock(true),
@@ -36,7 +36,7 @@ class StockController extends BaseController
$nextXDays = $usersService->GetUserSettings(GROCY_USER_ID)['stock_expring_soon_days'];
return $this->renderPage($response, 'stockentries', [
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
'locations' => $this->getDatabase()->locations()->orderBy('name'),
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
@@ -54,7 +54,7 @@ class StockController extends BaseController
$productBarcodes = $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
return $this->renderPage($response, 'purchase', [
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'barcodes' => $productBarcodes,
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
'locations' => $this->getDatabase()->locations()->orderBy('name')
@@ -67,7 +67,7 @@ class StockController extends BaseController
$productBarcodes = $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
return $this->renderPage($response, 'consume', [
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'barcodes' => $productBarcodes,
'recipes' => $this->getDatabase()->recipes()->orderBy('name'),
'locations' => $this->getDatabase()->locations()->orderBy('name')
@@ -80,7 +80,7 @@ class StockController extends BaseController
$productBarcodes = $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
return $this->renderPage($response, 'transfer', [
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'barcodes' => $productBarcodes,
'recipes' => $this->getDatabase()->recipes()->orderBy('name'),
'locations' => $this->getDatabase()->locations()->orderBy('name')
@@ -93,7 +93,7 @@ class StockController extends BaseController
$productBarcodes = $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
return $this->renderPage($response, 'inventory', [
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'barcodes' => $productBarcodes,
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
'locations' => $this->getDatabase()->locations()->orderBy('name')
@@ -104,7 +104,7 @@ class StockController extends BaseController
{
return $this->renderPage($response, 'stockentryform', [
'stockEntry' => $this->getDatabase()->stock()->where('id', $args['entryId'])->fetch(),
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
'locations' => $this->getDatabase()->locations()->orderBy('name')
]);
@@ -120,7 +120,7 @@ class StockController extends BaseController
return $this->renderPage($response, 'shoppinglist', [
'listItems' => $this->getDatabase()->shopping_list()->where('shopping_list_id = :1', $listId),
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
'missingProducts' => $this->getStockService()->GetMissingProducts(),
'productGroups' => $this->getDatabase()->product_groups()->orderBy('name'),
@@ -174,7 +174,7 @@ class StockController extends BaseController
{
return $this->renderPage($response, 'productgroups', [
'productGroups' => $this->getDatabase()->product_groups()->orderBy('name'),
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'userfields' => $this->getUserfieldsService()->GetFields('product_groups'),
'userfieldValues' => $this->getUserfieldsService()->GetAllValues('product_groups')
]);
@@ -200,7 +200,7 @@ class StockController extends BaseController
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
'userfields' => $this->getUserfieldsService()->GetFields('products'),
- 'products' => $this->getDatabase()->products()->where('parent_product_id IS NULL')->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('parent_product_id IS NULL and active = 1')->orderBy('name'),
'isSubProductOfOthers' => false,
'mode' => 'create'
]);
@@ -217,7 +217,7 @@ class StockController extends BaseController
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
'userfields' => $this->getUserfieldsService()->GetFields('products'),
- 'products' => $this->getDatabase()->products()->where('id != :1 AND parent_product_id IS NULL', $product->id)->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('id != :1 AND parent_product_id IS NULL and active = 1', $product->id)->orderBy('name'),
'isSubProductOfOthers' => $this->getDatabase()->products()->where('parent_product_id = :1', $product->id)->count() !== 0,
'mode' => 'edit',
'quConversions' => $this->getDatabase()->quantity_unit_conversions()
@@ -314,7 +314,7 @@ class StockController extends BaseController
if ($args['itemId'] == 'new')
{
return $this->renderPage($response, 'shoppinglistitemform', [
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name'),
'mode' => 'create'
]);
@@ -323,7 +323,7 @@ class StockController extends BaseController
{
return $this->renderPage($response, 'shoppinglistitemform', [
'listItem' => $this->getDatabase()->shopping_list($args['itemId']),
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name'),
'mode' => 'edit'
]);
@@ -357,7 +357,7 @@ class StockController extends BaseController
return $this->renderPage($response, 'stockjournal', [
'stockLog' => $this->getDatabase()->stock_log()->orderBy('row_created_timestamp', 'DESC'),
'locations' => $this->getDatabase()->locations()->orderBy('name'),
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name')
]);
}
@@ -365,7 +365,7 @@ class StockController extends BaseController
public function LocationContentSheet(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
{
return $this->renderPage($response, 'locationcontentsheet', [
- 'products' => $this->getDatabase()->products()->orderBy('name'),
+ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
'locations' => $this->getDatabase()->locations()->orderBy('name'),
'currentStockLocationContent' => $this->getStockService()->GetCurrentStockLocationContent()
diff --git a/migrations/0103.sql b/migrations/0103.sql
index 6e3efd1a..c98885dc 100644
--- a/migrations/0103.sql
+++ b/migrations/0103.sql
@@ -35,6 +35,7 @@ CREATE TABLE products (
name TEXT NOT NULL UNIQUE,
description TEXT,
product_group_id INTEGER,
+ active TINYINT NOT NULL DEFAULT 1,
location_id INTEGER NOT NULL,
shopping_location_id INTEGER,
qu_id_purchase INTEGER NOT NULL,
@@ -75,7 +76,7 @@ SELECT
IFNULL((SELECT SUM(amount) FROM stock WHERE product_id = s.product_id AND location_id = s.location_id AND open = 1), 0) AS amount_opened
FROM stock s
JOIN products p
- ON s.product_id = p.id
+ ON s.product_id = p.id and p.active = 1
GROUP BY IFNULL(s.location_id, p.location_id), s.product_id;
DROP VIEW stock_current;
@@ -95,9 +96,9 @@ FROM products_resolved pr
JOIN stock s
ON pr.sub_product_id = s.product_id
JOIN products p_parent
- ON pr.parent_product_id = p_parent.id
+ ON pr.parent_product_id = p_parent.id and p_parent.active = 1
JOIN products p_sub
- ON pr.sub_product_id = p_sub.id
+ ON pr.sub_product_id = p_sub.id and p_sub.active = 1
LEFT JOIN quantity_unit_conversions_resolved qucr
ON pr.sub_product_id = qucr.product_id
AND p_sub.qu_id_stock = qucr.from_qu_id
@@ -124,3 +125,21 @@ JOIN stock s
WHERE pr.parent_product_id != pr.sub_product_id
GROUP BY pr.sub_product_id
HAVING SUM(s.amount) > 0;
+
+DROP VIEW products_resolved;
+CREATE VIEW products_resolved AS
+SELECT
+ p.parent_product_id parent_product_id,
+ p.id as sub_product_id
+FROM products p
+ WHERE p.parent_product_id IS NOT NULL
+ and p.active = 1
+
+UNION
+
+SELECT
+ p.id parent_product_id,
+ p.id as sub_product_id
+FROM products p
+ WHERE p.parent_product_id IS NULL
+ AND p.active = 1;
diff --git a/migrations/0104.sql b/migrations/0104.sql
index 6352549e..17a3260c 100644
--- a/migrations/0104.sql
+++ b/migrations/0104.sql
@@ -77,7 +77,8 @@ SELECT
rp.note,
rp.variable_amount AS recipe_variable_amount,
rp.only_check_single_unit_in_stock,
- rp.amount * (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) * IFNULL(p.calories, 0) AS calories
+ rp.amount * (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) * IFNULL(p.calories, 0) AS calories,
+ p.active AS product_active
FROM recipes r
JOIN recipes_nestings_resolved rnr
ON r.id = rnr.recipe_id
@@ -125,7 +126,8 @@ SELECT
rp.note,
rp.variable_amount AS recipe_variable_amount,
rp.only_check_single_unit_in_stock,
- rp.amount * (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) * IFNULL(p.calories, 0) AS calories
+ rp.amount * (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) * IFNULL(p.calories, 0) AS calories,
+ p.active AS product_active
FROM recipes r
JOIN recipes_nestings_resolved rnr
ON r.id = rnr.recipe_id
diff --git a/public/viewjs/products.js b/public/viewjs/products.js
index 2a040a7d..ace04d3d 100644
--- a/public/viewjs/products.js
+++ b/public/viewjs/products.js
@@ -49,7 +49,7 @@ $(document).on('click', '.product-delete-button', function (e)
if (stockAmount.toString() == "0")
{
bootbox.confirm({
- message: __t('Are you sure to delete product "%s"?', objectName),
+ message: __t('Are you sure you want to deactivate this product "%s"?', objectName),
closeButton: false,
buttons: {
confirm: {
@@ -65,7 +65,9 @@ $(document).on('click', '.product-delete-button', function (e)
{
if (result === true)
{
- Grocy.Api.Delete('objects/products/' + objectId, {},
+ jsonData = {};
+ jsonData.active = 0;
+ Grocy.Api.Put('objects/products/' + objectId, jsonData,
function (result)
{
window.location.href = U('/products');
@@ -82,8 +84,8 @@ $(document).on('click', '.product-delete-button', function (e)
else
{
bootbox.alert({
- title: __t('Delete not possible'),
- message: __t('This product cannot be deleted because it is in stock, please remove the stock amount first.') + '
' + __t('Stock amount') + ': ' + stockAmount + ' ' + __n(stockAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural),
+ title: __t('Deactivation not possible'),
+ message: __t('This product cannot be deactivated because it is in stock, please remove the stock amount first.') + '
' + __t('Stock amount') + ': ' + stockAmount + ' ' + __n(stockAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural),
closeButton: false
});
}
diff --git a/services/StockService.php b/services/StockService.php
index 2f12c198..2abfae88 100644
--- a/services/StockService.php
+++ b/services/StockService.php
@@ -96,7 +96,7 @@ class StockService extends BaseService
{
if (!$this->ProductExists($productId))
{
- throw new \Exception('Product does not exist');
+ throw new \Exception('Product does not exist or is inactive');
}
$stockCurrentRow = FindObjectinArrayByPropertyValue($this->GetCurrentStock(), 'product_id', $productId);
@@ -168,7 +168,7 @@ class StockService extends BaseService
{
if (!$this->ProductExists($productId))
{
- throw new \Exception('Product does not exist');
+ throw new \Exception('Product does not exist or is inactive');
}
$returnData = array();
@@ -220,7 +220,7 @@ class StockService extends BaseService
{
if (!$this->ProductExists($productId))
{
- throw new \Exception('Product does not exist');
+ throw new \Exception('Product does not exist or is inactive');
}
// Tare weight handling
@@ -305,7 +305,7 @@ class StockService extends BaseService
{
if (!$this->ProductExists($productId))
{
- throw new \Exception('Product does not exist');
+ throw new \Exception('Product does not exist or is inactive');
}
if ($locationId !== null && !$this->LocationExists($locationId))
@@ -424,7 +424,7 @@ class StockService extends BaseService
{
if (!$this->ProductExists($productId))
{
- throw new \Exception('Product does not exist');
+ throw new \Exception('Product does not exist or is inactive');
}
if (!$this->LocationExists($locationIdFrom))
@@ -681,7 +681,7 @@ class StockService extends BaseService
{
if (!$this->ProductExists($productId))
{
- throw new \Exception('Product does not exist');
+ throw new \Exception('Product does not exist or is inactive');
}
$productDetails = (object)$this->GetProductDetails($productId);
@@ -737,7 +737,7 @@ class StockService extends BaseService
{
if (!$this->ProductExists($productId))
{
- throw new \Exception('Product does not exist');
+ throw new \Exception('Product does not exist or is inactive');
}
$productStockAmountUnopened = $this->getDatabase()->stock()->where('product_id = :1 AND open = 0', $productId)->sum('amount');
@@ -917,7 +917,7 @@ class StockService extends BaseService
if (!$this->ProductExists($productId))
{
- throw new \Exception('Product does not exist');
+ throw new \Exception('Product does not exist or is inactive');
}
$alreadyExistingEntry = $this->getDatabase()->shopping_list()->where('product_id = :1 AND shopping_list_id = :2', $productId, $listId)->fetch();
@@ -943,7 +943,7 @@ class StockService extends BaseService
private function ProductExists($productId)
{
- $productRow = $this->getDatabase()->products()->where('id = :1', $productId)->fetch();
+ $productRow = $this->getDatabase()->products()->where('id = :1 and active = 1', $productId)->fetch();
return $productRow !== null;
}
diff --git a/views/productform.blade.php b/views/productform.blade.php
index 5851f704..6af4090c 100644
--- a/views/productform.blade.php
+++ b/views/productform.blade.php
@@ -46,6 +46,14 @@