Optimized GROCY_FEATURE_FLAG_STOCK handling (closes #966)

This commit is contained in:
Bernd Bestel 2020-12-21 20:13:49 +01:00
parent 7478d9bb38
commit 694b78f72a
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
11 changed files with 90 additions and 99 deletions

View File

@ -161,6 +161,9 @@
- Users can now have a picture (will then be shown next to the current user name instead of the generic user icon)
- Prefilled number inputs now use sensible decimal places (max. the configured decimals while hiding trailing zeros where appropriate, means if you never use partial amounts for a product, you'll never see decimals for it)
- Improved / more precise validation messages for number inputs
- Optimized what's hidden when `GROCY_FEATURE_FLAG_STOCK` is disabled
- Products, quantity units and product groups are possible to use now
- Means you can use for example the shopping list, recipes and the meal plan with products while the "stock handling part" is hidden
- Ordering now happens case-insensitive
- The data path (previously fixed to the `data` folder) is now configurable, making it possible to run multiple grocy instances from the same directory (with different `config.php` files / different database, etc.) (thanks @fgrsnau)
- Via an environment variable `GROCY_DATAPATH` (higher priority)

View File

@ -126,6 +126,12 @@ var calendar = $("#calendar").fullCalendar({
costsAndCaloriesPerServing = '<h5 class="small text-truncate"><span class="locale-number locale-number-generic">' + resolvedRecipe.calories + '</span> kcal ' + __t('per serving') + '<h5>';
}
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK)
{
fulfillmentIconHtml = "";
fulfillmentInfoHtml = "";
}
element.html('\
<div> \
<h5 class="text-truncate">' + recipe.name + '<h5> \
@ -274,6 +280,12 @@ var calendar = $("#calendar").fullCalendar({
{
$("#calendar").fullCalendar("gotoDate", GetUriParam("week"));
}
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK)
{
$(".recipe-order-missing-button").addClass("d-none");
$(".recipe-consume-button").addClass("d-none");
}
},
});

View File

@ -546,7 +546,7 @@ $("img.barcode").each(function()
img.attr("src", dummyCanvas.toDataURL("image/png"));
});
if ($(window).width() < 768)
if ($(window).width() < 768 || !Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK)
{
$("#filter-container").removeClass("border-bottom");
}

View File

@ -145,8 +145,6 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
if (productId)
{
Grocy.Components.ProductCard.Refresh(productId);
Grocy.Api.Get('stock/products/' + productId,
function(productDetails)
{

View File

@ -33,7 +33,16 @@ $app->group('', function (RouteCollectorProxy $group) {
$group->get('/files/{group}/{fileName}', '\Grocy\Controllers\FilesApiController:ShowFile');
// Stock routes
// Stock master data routes
$group->get('/products', '\Grocy\Controllers\StockController:ProductsList');
$group->get('/product/{productId}', '\Grocy\Controllers\StockController:ProductEditForm');
$group->get('/quantityunits', '\Grocy\Controllers\StockController:QuantityUnitsList');
$group->get('/quantityunit/{quantityunitId}', '\Grocy\Controllers\StockController:QuantityUnitEditForm');
$group->get('/quantityunitconversion/{quConversionId}', '\Grocy\Controllers\StockController:QuantityUnitConversionEditForm');
$group->get('/productgroups', '\Grocy\Controllers\StockController:ProductGroupsList');
$group->get('/productgroup/{productGroupId}', '\Grocy\Controllers\StockController:ProductGroupEditForm');
// Stock handling routes
if (GROCY_FEATURE_FLAG_STOCK)
{
$group->get('/stockoverview', '\Grocy\Controllers\StockController:Overview');
@ -43,21 +52,14 @@ $app->group('', function (RouteCollectorProxy $group) {
$group->get('/transfer', '\Grocy\Controllers\StockController:Transfer');
$group->get('/inventory', '\Grocy\Controllers\StockController:Inventory');
$group->get('/stockentry/{entryId}', '\Grocy\Controllers\StockController:StockEntryEditForm');
$group->get('/products', '\Grocy\Controllers\StockController:ProductsList');
$group->get('/product/{productId}', '\Grocy\Controllers\StockController:ProductEditForm');
$group->get('/productbarcodes/{productBarcodeId}', '\Grocy\Controllers\StockController:ProductBarcodesEditForm');
$group->get('/stocksettings', '\Grocy\Controllers\StockController:StockSettings');
$group->get('/locations', '\Grocy\Controllers\StockController:LocationsList');
$group->get('/location/{locationId}', '\Grocy\Controllers\StockController:LocationEditForm');
$group->get('/quantityunits', '\Grocy\Controllers\StockController:QuantityUnitsList');
$group->get('/quantityunit/{quantityunitId}', '\Grocy\Controllers\StockController:QuantityUnitEditForm');
$group->get('/quantityunitconversion/{quConversionId}', '\Grocy\Controllers\StockController:QuantityUnitConversionEditForm');
$group->get('/productgroups', '\Grocy\Controllers\StockController:ProductGroupsList');
$group->get('/productgroup/{productGroupId}', '\Grocy\Controllers\StockController:ProductGroupEditForm');
$group->get('/stockjournal', '\Grocy\Controllers\StockController:Journal');
$group->get('/locationcontentsheet', '\Grocy\Controllers\StockController:LocationContentSheet');
$group->get('/quantityunitpluraltesting', '\Grocy\Controllers\StockController:QuantityUnitPluralFormTesting');
$group->get('/stockjournal/summary', '\Grocy\Controllers\StockController:JournalSummary');
$group->get('/productbarcodes/{productBarcodeId}', '\Grocy\Controllers\StockController:ProductBarcodesEditForm');
}
// Stock price tracking
@ -178,88 +180,67 @@ $app->group('/api', function (RouteCollectorProxy $group) {
$group->delete('/user/settings/{settingKey}', '\Grocy\Controllers\UsersApiController:DeleteUserSetting');
// Stock
if (GROCY_FEATURE_FLAG_STOCK)
{
$group->get('/stock', '\Grocy\Controllers\StockApiController:CurrentStock');
$group->get('/stock/entry/{entryId}', '\Grocy\Controllers\StockApiController:StockEntry');
$group->put('/stock/entry/{entryId}', '\Grocy\Controllers\StockApiController:EditStockEntry');
$group->get('/stock/volatile', '\Grocy\Controllers\StockApiController:CurrentVolatileStock');
$group->get('/stock/products/{productId}', '\Grocy\Controllers\StockApiController:ProductDetails');
$group->get('/stock/products/{productId}/entries', '\Grocy\Controllers\StockApiController:ProductStockEntries');
$group->get('/stock/products/{productId}/locations', '\Grocy\Controllers\StockApiController:ProductStockLocations');
$group->get('/stock/products/{productId}/price-history', '\Grocy\Controllers\StockApiController:ProductPriceHistory');
$group->post('/stock/products/{productId}/add', '\Grocy\Controllers\StockApiController:AddProduct');
$group->post('/stock/products/{productId}/consume', '\Grocy\Controllers\StockApiController:ConsumeProduct');
$group->post('/stock/products/{productId}/transfer', '\Grocy\Controllers\StockApiController:TransferProduct');
$group->post('/stock/products/{productId}/inventory', '\Grocy\Controllers\StockApiController:InventoryProduct');
$group->post('/stock/products/{productId}/open', '\Grocy\Controllers\StockApiController:OpenProduct');
$group->post('/stock/products/{productIdToKeep}/merge/{productIdToRemove}', '\Grocy\Controllers\StockApiController:MergeProducts');
$group->get('/stock/products/by-barcode/{barcode}', '\Grocy\Controllers\StockApiController:ProductDetailsByBarcode');
$group->post('/stock/products/by-barcode/{barcode}/add', '\Grocy\Controllers\StockApiController:AddProductByBarcode');
$group->post('/stock/products/by-barcode/{barcode}/consume', '\Grocy\Controllers\StockApiController:ConsumeProductByBarcode');
$group->post('/stock/products/by-barcode/{barcode}/transfer', '\Grocy\Controllers\StockApiController:TransferProductByBarcode');
$group->post('/stock/products/by-barcode/{barcode}/inventory', '\Grocy\Controllers\StockApiController:InventoryProductByBarcode');
$group->post('/stock/products/by-barcode/{barcode}/open', '\Grocy\Controllers\StockApiController:OpenProductByBarcode');
$group->get('/stock/bookings/{bookingId}', '\Grocy\Controllers\StockApiController:StockBooking');
$group->post('/stock/bookings/{bookingId}/undo', '\Grocy\Controllers\StockApiController:UndoBooking');
$group->get('/stock/transactions/{transactionId}', '\Grocy\Controllers\StockApiController:StockTransactions');
$group->post('/stock/transactions/{transactionId}/undo', '\Grocy\Controllers\StockApiController:UndoTransaction');
$group->get('/stock/barcodes/external-lookup/{barcode}', '\Grocy\Controllers\StockApiController:ExternalBarcodeLookup');
}
$group->get('/stock', '\Grocy\Controllers\StockApiController:CurrentStock');
$group->get('/stock/entry/{entryId}', '\Grocy\Controllers\StockApiController:StockEntry');
$group->put('/stock/entry/{entryId}', '\Grocy\Controllers\StockApiController:EditStockEntry');
$group->get('/stock/volatile', '\Grocy\Controllers\StockApiController:CurrentVolatileStock');
$group->get('/stock/products/{productId}', '\Grocy\Controllers\StockApiController:ProductDetails');
$group->get('/stock/products/{productId}/entries', '\Grocy\Controllers\StockApiController:ProductStockEntries');
$group->get('/stock/products/{productId}/locations', '\Grocy\Controllers\StockApiController:ProductStockLocations');
$group->get('/stock/products/{productId}/price-history', '\Grocy\Controllers\StockApiController:ProductPriceHistory');
$group->post('/stock/products/{productId}/add', '\Grocy\Controllers\StockApiController:AddProduct');
$group->post('/stock/products/{productId}/consume', '\Grocy\Controllers\StockApiController:ConsumeProduct');
$group->post('/stock/products/{productId}/transfer', '\Grocy\Controllers\StockApiController:TransferProduct');
$group->post('/stock/products/{productId}/inventory', '\Grocy\Controllers\StockApiController:InventoryProduct');
$group->post('/stock/products/{productId}/open', '\Grocy\Controllers\StockApiController:OpenProduct');
$group->post('/stock/products/{productIdToKeep}/merge/{productIdToRemove}', '\Grocy\Controllers\StockApiController:MergeProducts');
$group->get('/stock/products/by-barcode/{barcode}', '\Grocy\Controllers\StockApiController:ProductDetailsByBarcode');
$group->post('/stock/products/by-barcode/{barcode}/add', '\Grocy\Controllers\StockApiController:AddProductByBarcode');
$group->post('/stock/products/by-barcode/{barcode}/consume', '\Grocy\Controllers\StockApiController:ConsumeProductByBarcode');
$group->post('/stock/products/by-barcode/{barcode}/transfer', '\Grocy\Controllers\StockApiController:TransferProductByBarcode');
$group->post('/stock/products/by-barcode/{barcode}/inventory', '\Grocy\Controllers\StockApiController:InventoryProductByBarcode');
$group->post('/stock/products/by-barcode/{barcode}/open', '\Grocy\Controllers\StockApiController:OpenProductByBarcode');
$group->get('/stock/bookings/{bookingId}', '\Grocy\Controllers\StockApiController:StockBooking');
$group->post('/stock/bookings/{bookingId}/undo', '\Grocy\Controllers\StockApiController:UndoBooking');
$group->get('/stock/transactions/{transactionId}', '\Grocy\Controllers\StockApiController:StockTransactions');
$group->post('/stock/transactions/{transactionId}/undo', '\Grocy\Controllers\StockApiController:UndoTransaction');
$group->get('/stock/barcodes/external-lookup/{barcode}', '\Grocy\Controllers\StockApiController:ExternalBarcodeLookup');
// Shopping list
if (GROCY_FEATURE_FLAG_SHOPPINGLIST)
{
$group->post('/stock/shoppinglist/add-missing-products', '\Grocy\Controllers\StockApiController:AddMissingProductsToShoppingList');
$group->post('/stock/shoppinglist/add-overdue-products', '\Grocy\Controllers\StockApiController:AddOverdueProductsToShoppingList');
$group->post('/stock/shoppinglist/add-expired-products', '\Grocy\Controllers\StockApiController:AddExpiredProductsToShoppingList');
$group->post('/stock/shoppinglist/clear', '\Grocy\Controllers\StockApiController:ClearShoppingList');
$group->post('/stock/shoppinglist/add-product', '\Grocy\Controllers\StockApiController:AddProductToShoppingList');
$group->post('/stock/shoppinglist/remove-product', '\Grocy\Controllers\StockApiController:RemoveProductFromShoppingList');
}
$group->post('/stock/shoppinglist/add-missing-products', '\Grocy\Controllers\StockApiController:AddMissingProductsToShoppingList');
$group->post('/stock/shoppinglist/add-overdue-products', '\Grocy\Controllers\StockApiController:AddOverdueProductsToShoppingList');
$group->post('/stock/shoppinglist/add-expired-products', '\Grocy\Controllers\StockApiController:AddExpiredProductsToShoppingList');
$group->post('/stock/shoppinglist/clear', '\Grocy\Controllers\StockApiController:ClearShoppingList');
$group->post('/stock/shoppinglist/add-product', '\Grocy\Controllers\StockApiController:AddProductToShoppingList');
$group->post('/stock/shoppinglist/remove-product', '\Grocy\Controllers\StockApiController:RemoveProductFromShoppingList');
// Recipes
if (GROCY_FEATURE_FLAG_RECIPES)
{
$group->post('/recipes/{recipeId}/add-not-fulfilled-products-to-shoppinglist', '\Grocy\Controllers\RecipesApiController:AddNotFulfilledProductsToShoppingList');
$group->get('/recipes/{recipeId}/fulfillment', '\Grocy\Controllers\RecipesApiController:GetRecipeFulfillment');
$group->post('/recipes/{recipeId}/consume', '\Grocy\Controllers\RecipesApiController:ConsumeRecipe');
$group->get('/recipes/fulfillment', '\Grocy\Controllers\RecipesApiController:GetRecipeFulfillment');
}
$group->post('/recipes/{recipeId}/add-not-fulfilled-products-to-shoppinglist', '\Grocy\Controllers\RecipesApiController:AddNotFulfilledProductsToShoppingList');
$group->get('/recipes/{recipeId}/fulfillment', '\Grocy\Controllers\RecipesApiController:GetRecipeFulfillment');
$group->post('/recipes/{recipeId}/consume', '\Grocy\Controllers\RecipesApiController:ConsumeRecipe');
$group->get('/recipes/fulfillment', '\Grocy\Controllers\RecipesApiController:GetRecipeFulfillment');
// Chores
if (GROCY_FEATURE_FLAG_CHORES)
{
$group->get('/chores', '\Grocy\Controllers\ChoresApiController:Current');
$group->get('/chores/{choreId}', '\Grocy\Controllers\ChoresApiController:ChoreDetails');
$group->post('/chores/{choreId}/execute', '\Grocy\Controllers\ChoresApiController:TrackChoreExecution');
$group->post('/chores/executions/{executionId}/undo', '\Grocy\Controllers\ChoresApiController:UndoChoreExecution');
$group->post('/chores/executions/calculate-next-assignments', '\Grocy\Controllers\ChoresApiController:CalculateNextExecutionAssignments');
}
$group->get('/chores', '\Grocy\Controllers\ChoresApiController:Current');
$group->get('/chores/{choreId}', '\Grocy\Controllers\ChoresApiController:ChoreDetails');
$group->post('/chores/{choreId}/execute', '\Grocy\Controllers\ChoresApiController:TrackChoreExecution');
$group->post('/chores/executions/{executionId}/undo', '\Grocy\Controllers\ChoresApiController:UndoChoreExecution');
$group->post('/chores/executions/calculate-next-assignments', '\Grocy\Controllers\ChoresApiController:CalculateNextExecutionAssignments');
// Batteries
if (GROCY_FEATURE_FLAG_BATTERIES)
{
$group->get('/batteries', '\Grocy\Controllers\BatteriesApiController:Current');
$group->get('/batteries/{batteryId}', '\Grocy\Controllers\BatteriesApiController:BatteryDetails');
$group->post('/batteries/{batteryId}/charge', '\Grocy\Controllers\BatteriesApiController:TrackChargeCycle');
$group->post('/batteries/charge-cycles/{chargeCycleId}/undo', '\Grocy\Controllers\BatteriesApiController:UndoChargeCycle');
}
$group->get('/batteries', '\Grocy\Controllers\BatteriesApiController:Current');
$group->get('/batteries/{batteryId}', '\Grocy\Controllers\BatteriesApiController:BatteryDetails');
$group->post('/batteries/{batteryId}/charge', '\Grocy\Controllers\BatteriesApiController:TrackChargeCycle');
$group->post('/batteries/charge-cycles/{chargeCycleId}/undo', '\Grocy\Controllers\BatteriesApiController:UndoChargeCycle');
// Tasks
if (GROCY_FEATURE_FLAG_TASKS)
{
$group->get('/tasks', '\Grocy\Controllers\TasksApiController:Current');
$group->post('/tasks/{taskId}/complete', '\Grocy\Controllers\TasksApiController:MarkTaskAsCompleted');
$group->post('/tasks/{taskId}/undo', '\Grocy\Controllers\TasksApiController:UndoTask');
}
$group->get('/tasks', '\Grocy\Controllers\TasksApiController:Current');
$group->post('/tasks/{taskId}/complete', '\Grocy\Controllers\TasksApiController:MarkTaskAsCompleted');
$group->post('/tasks/{taskId}/undo', '\Grocy\Controllers\TasksApiController:UndoTask');
// Calendar
if (GROCY_FEATURE_FLAG_CALENDAR)
{
$group->get('/calendar/ical', '\Grocy\Controllers\CalendarApiController:Ical')->setName('calendar-ical');
$group->get('/calendar/ical/sharing-link', '\Grocy\Controllers\CalendarApiController:IcalSharingLink');
}
$group->get('/calendar/ical', '\Grocy\Controllers\CalendarApiController:Ical')->setName('calendar-ical');
$group->get('/calendar/ical/sharing-link', '\Grocy\Controllers\CalendarApiController:IcalSharingLink');
})->add(JsonMiddleware::class);
// Handle CORS preflight OPTIONS requests

View File

@ -362,7 +362,6 @@
</a>
<ul id="top-nav-manager-master-data"
class="sidenav-second-level collapse">
@if(GROCY_FEATURE_FLAG_STOCK)
<li data-nav-for-page="products"
data-sub-menu-of="#top-nav-manager-master-data">
<a class="nav-link discrete-link"
@ -370,6 +369,7 @@
<span class="nav-link-text">{{ $__t('Products') }}</span>
</a>
</li>
@if(GROCY_FEATURE_FLAG_STOCK)
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
<li data-nav-for-page="locations"
data-sub-menu-of="#top-nav-manager-master-data">
@ -388,6 +388,7 @@
</a>
</li>
@endif
@endif
<li data-nav-for-page="quantityunits"
data-sub-menu-of="#top-nav-manager-master-data">
<a class="nav-link discrete-link"
@ -402,7 +403,6 @@
<span class="nav-link-text">{{ $__t('Product groups') }}</span>
</a>
</li>
@endif
@if(GROCY_FEATURE_FLAG_CHORES)
<li data-nav-for-page="chores"
data-sub-menu-of="#top-nav-manager-master-data">

View File

@ -426,7 +426,7 @@
</div>
<div class="col-lg-6 col-xs-12 @if($mode == 'create') d-none @endif">
<div class="row">
<div class="row @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif">
<div class="col">
<div class="title-related-links">
<h4>
@ -533,7 +533,7 @@
</div>
</div>
<div class="row mt-5">
<div class="row @if(GROCY_FEATURE_FLAG_STOCK) mt-5 @endif">
<div class="col">
<div class="title-related-links">
<h4>

View File

@ -46,7 +46,7 @@
'nextInputSelector' => '#amount'
))
<div class="form-group mb-2">
<div class="form-group mb-2 @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif">
<div class="custom-control custom-checkbox">
<input @if($mode=='edit'
&&
@ -77,7 +77,7 @@
value="@if($mode == 'edit'){{ $recipePos->variable_amount }}@endif">
</div>
<div class="form-group">
<div class="form-group @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif">
<div class="custom-control custom-checkbox">
<input @if($mode=='edit'
&&

View File

@ -108,7 +108,7 @@
</th>
<th>{{ $__t('Name') }}</th>
<th>{{ $__t('Desired servings') }}</th>
<th>{{ $__t('Requirements fulfilled') }}</th>
<th class="@if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif">{{ $__t('Requirements fulfilled') }}</th>
<th class="d-none">Hidden status for sorting of "Requirements fulfilled" column</th>
<th class="d-none">Hidden status for filtering by status</th>
<th class="d-none">Hidden recipe ingredient product names</th>
@ -145,7 +145,7 @@
<td>
{{ $recipe->desired_servings }}
</td>
<td>
<td class="@if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif">
@if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1)<i class="fas fa-check text-success"></i>@elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1)<i class="fas fa-exclamation text-warning"></i>@else<i class="fas fa-times text-danger"></i>@endif
<span class="timeago-contextual">@if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1){{ $__t('Enough in stock') }}@elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1){{ $__n(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count, 'Not enough in stock, %s ingredient missing but already on the shopping list', 'Not enough in stock, %s ingredients missing but already on the shopping list') }}@else{{ $__n(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count, 'Not enough in stock, %s ingredient missing', 'Not enough in stock, %s ingredients missing') }}@endif</span>
</td>
@ -236,7 +236,7 @@
<div class="d-flex justify-content-between align-items-center">
<h3 class="card-title mb-0">{{ $recipe->name }}</h3>
<div class="card-icons d-flex flex-wrap justify-content-end flex-shrink-1">
<a class="recipe-consume hide-when-embedded @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 0) disabled @endif"
<a class="@if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif recipe-consume hide-when-embedded @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 0) disabled @endif"
href="#"
data-toggle="tooltip"
title="{{ $__t('Consume all ingredients needed by this recipe') }}"
@ -244,7 +244,7 @@
data-recipe-name="{{ $recipe->name }}">
<i class="fas fa-utensils"></i>
</a>
<a class="recipe-shopping-list hide-when-embedded @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) disabled @endif"
<a class="@if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif recipe-shopping-list hide-when-embedded @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) disabled @endif"
href="#"
data-toggle="tooltip"
title="{{ $__t('Put missing products on shopping list') }}"
@ -409,8 +409,10 @@
<span class="locale-number locale-number-quantity-amount">@if($selectedRecipePosition->recipe_amount == round($selectedRecipePosition->recipe_amount, 2)){{ round($selectedRecipePosition->recipe_amount, 2) }}@else{{ $selectedRecipePosition->recipe_amount }}@endif</span>
@endif
{{ $__n($selectedRecipePosition->recipe_amount, FindObjectInArrayByPropertyValue($quantityUnits, 'id', $selectedRecipePosition->qu_id)->name, FindObjectInArrayByPropertyValue($quantityUnits, 'id', $selectedRecipePosition->qu_id)->name_plural) }} {{ FindObjectInArrayByPropertyValue($products, 'id', $selectedRecipePosition->product_id)->name }}
@if(GROCY_FEATURE_FLAG_STOCK)
@if($selectedRecipePosition->need_fulfilled == 1)<i class="fas fa-check text-success"></i>@elseif($selectedRecipePosition->need_fulfilled_with_shopping_list == 1)<i class="fas fa-exclamation text-warning"></i>@else<i class="fas fa-times text-danger"></i>@endif
<span class="timeago-contextual">@if(FindObjectInArrayByPropertyValue($recipePositionsResolved, 'recipe_pos_id', $selectedRecipePosition->id)->need_fulfilled == 1) {{ $__t('Enough in stock') }} @else {{ $__t('Not enough in stock (not included in costs), %1$s missing, %2$s already on shopping list', round(FindObjectInArrayByPropertyValue($recipePositionsResolved, 'recipe_pos_id', $selectedRecipePosition->id)->missing_amount, 2), round(FindObjectInArrayByPropertyValue($recipePositionsResolved, 'recipe_pos_id', $selectedRecipePosition->id)->amount_on_shopping_list, 2)) }} @endif</span>
@endif
@if($selectedRecipePosition->need_fulfilled == 1 && GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) <span class="float-right font-italic ml-2 locale-number locale-number-currency">{{ $selectedRecipePosition->costs }}</span> @endif
<span class="float-right font-italic"><span class="locale-number locale-number-quantity-amount">{{ $selectedRecipePosition->calories }} {{ $__t('Calories') }}</span></span>
@if(!empty($selectedRecipePosition->recipe_variable_amount))

View File

@ -76,7 +76,7 @@
class="border-top border-bottom my-2 py-1">
<div id="table-filter-row"
data-status-filter="belowminstockamount"
class="collapse d-md-inline-block normal-message status-filter-message responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif"><span class="d-block d-md-none">{{count($missingProducts)}} <i class="fas fa-exclamation-circle"></i></span><span class="d-none d-md-block">{{ $__n(count($missingProducts), '%s product is below defined min. stock amount', '%s products are below defined min. stock amount') }}</span></div>
class="collapse normal-message status-filter-message responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @else d-md-inline-block @endif"><span class="d-block d-md-none">{{count($missingProducts)}} <i class="fas fa-exclamation-circle"></i></span><span class="d-none d-md-block">{{ $__n(count($missingProducts), '%s product is below defined min. stock amount', '%s products are below defined min. stock amount') }}</span></div>
<div id="related-links"
class="float-right mt-1 collapse d-md-block">
<a class="btn btn-primary responsive-button btn-sm mb-1 show-as-dialog-link"

View File

@ -57,7 +57,7 @@
value="1">
@endif
<div class="@if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif">
<div>
@php if($mode == 'edit') { $productId = $listItem->product_id; } else { $productId = ''; } @endphp
@include('components.productpicker', array(
'products' => $products,
@ -94,10 +94,5 @@
</form>
</div>
@if(GROCY_FEATURE_FLAG_STOCK)
<div class="col-xs-12 col-md-6 col-xl-4 hide-when-embedded">
@include('components.productcard')
</div>
@endif
</div>
@stop