mirror of
https://github.com/grocy/grocy.git
synced 2026-04-07 05:16:15 +02:00
Allow products to be deactivated instead of deleted
This commit is contained in:
parent
502622da69
commit
c3f77591ee
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.') + '<br><br>' + __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.') + '<br><br>' + __t('Stock amount') + ': ' + stockAmount + ' ' + __n(stockAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural),
|
||||
closeButton: false
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,14 @@
|
|||
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input type="hidden" name="active" value="1">
|
||||
<input @if($mode == 'create') checked @elseif($mode == 'edit' && $product->active == 1) checked @endif class="form-check-input" type="checkbox" id="active" name="active" value="1">
|
||||
<label class="form-check-label" for="active">{{ $__t('Active') }}</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@php $prefillById = ''; if($mode=='edit') { $prefillById = $product->parent_product_id; } @endphp
|
||||
@php
|
||||
$hint = '';
|
||||
|
|
|
|||
|
|
@ -81,12 +81,12 @@
|
|||
<a class="btn btn-info btn-sm" href="{{ $U('/product/') }}{{ $product->id }}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<a class="btn btn-danger btn-sm product-delete-button" href="#" data-product-id="{{ $product->id }}" data-product-name="{{ $product->name }}">
|
||||
<a class="btn btn-danger btn-sm product-delete-button @if($product->active == 0) disabled @endif" href="#" data-product-id="{{ $product->id }}" data-product-name="{{ $product->name }}">
|
||||
<i class="fas fa-trash"></i>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ $product->name }}@if(!empty($product->picture_file_name)) <i class="fas fa-image text-muted"></i>@endif
|
||||
@if($product->active == 0) (deactivated) @endif {{ $product->name }}@if(!empty($product->picture_file_name)) <i class="fas fa-image text-muted"></i>@endif
|
||||
</td>
|
||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif">
|
||||
{{ FindObjectInArrayByPropertyValue($locations, 'id', $product->location_id)->name }}
|
||||
|
|
|
|||
|
|
@ -310,6 +310,9 @@
|
|||
<h6 class="mb-2 mt-2 @if($hasIngredientGroups) ml-3 @else ml-1 @endif"><strong>{{ $selectedRecipePosition->product_group }}</strong></h6>
|
||||
@endif
|
||||
<li class="list-group-item px-0 @if($hasIngredientGroups && $hasProductGroups) ml-4 @elseif($hasIngredientGroups || $hasProductGroups) ml-2 @else ml-0 @endif">
|
||||
@if($selectedRecipePosition->product_active == 0)
|
||||
<div class="small text-muted font-italic">{{ $__t('Deactivated Product') }}</div>
|
||||
@endif
|
||||
@php
|
||||
$product = FindObjectInArrayByPropertyValue($products, 'id', $selectedRecipePosition->product_id);
|
||||
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user