Improvements (#1049)

* Fixes #1035: Check available amount after filtering by stock_entry_id

* Fixes #1036: Remove stock-related buttons/options from Shopping-list  if FEATURE_FLAG_STOCK is disabled

* Fixes #1010: Repair recipe-picture upload.

* Fixes #958: Disable auto-reload of equipments-page.

* Fix uncaught exception in locationpicker.js

* Fixes #761 and #762: Add "Remove exact amount" for products with tare weight handling and use it for recipe-consumption.

* Fixes #1048: Repair product-group-filter on "Master Data"/Products

* Renamed variable

Co-authored-by: Bernd Bestel <bernd@berrnd.de>
This commit is contained in:
fipwmaqzufheoxq92ebc
2020-10-14 17:48:37 +02:00
committed by GitHub
parent a66a4d0c22
commit a85998dd40
14 changed files with 125 additions and 84 deletions

View File

@@ -263,7 +263,15 @@ class StockApiController extends BaseApiController
$recipeId = $requestBody['recipe_id']; $recipeId = $requestBody['recipe_id'];
} }
$bookingId = $this->getStockService()->ConsumeProduct($args['productId'], $requestBody['amount'], $spoiled, $transactionType, $specificStockEntryId, $recipeId, $locationId); $consumeExact = false;
if (array_key_exists('exact_amount', $requestBody))
{
$consumeExact = $requestBody['exact_amount'];
}
$transactionId = null;
$bookingId = $this->getStockService()->ConsumeProduct($args['productId'], $requestBody['amount'], $spoiled, $transactionType, $specificStockEntryId, $recipeId, $locationId, $transactionId, false, $consumeExact);
return $this->ApiResponse($response, $this->getDatabase()->stock_log($bookingId)); return $this->ApiResponse($response, $this->getDatabase()->stock_log($bookingId));
} }
catch (\Exception $ex) catch (\Exception $ex)

View File

@@ -15,8 +15,10 @@
// Check if the database has changed once a minute // Check if the database has changed once a minute
// If a change is detected, reload the current page, but only if already idling for at least 50 seconds, // If a change is detected, reload the current page, but only if already idling for at least 50 seconds,
// when there is no unsaved form data and when the user enabled auto reloading // when there is no unsaved form data and when the user enabled auto reloading
setInterval(function() if (Grocy.DbChangedHandlingEnabledForPage)
{ {
setInterval(function()
{
Grocy.Api.Get('system/db-changed-time', Grocy.Api.Get('system/db-changed-time',
function(result) function(result)
{ {
@@ -39,7 +41,8 @@ setInterval(function()
console.error(xhr); console.error(xhr);
} }
); );
}, 60000); }, 60000);
}
Grocy.IdleTime = 0; Grocy.IdleTime = 0;
Grocy.ResetIdleTime = function() Grocy.ResetIdleTime = function()

View File

@@ -9,6 +9,7 @@
var jsonData = {}; var jsonData = {};
jsonData.amount = jsonForm.amount; jsonData.amount = jsonForm.amount;
jsonData.exact_amount = (jsonForm.exact_amount == "on");
jsonData.spoiled = $('#spoiled').is(':checked'); jsonData.spoiled = $('#spoiled').is(':checked');
if ($("#use_specific_stock_entry").is(":checked")) if ($("#use_specific_stock_entry").is(":checked"))
@@ -70,7 +71,7 @@
$("#use_specific_stock_entry").click(); $("#use_specific_stock_entry").click();
} }
if (productDetails.product.enable_tare_weight_handling == 1) if (productDetails.product.enable_tare_weight_handling == 1 && !jsonData.exact_amount)
{ {
var successMessage = __t('Removed %1$s of %2$s from stock', Math.abs(jsonForm.amount - (parseFloat(productDetails.product.tare_weight) + parseFloat(productDetails.stock_amount))) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse.transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>'; var successMessage = __t('Removed %1$s of %2$s from stock', Math.abs(jsonForm.amount - (parseFloat(productDetails.product.tare_weight) + parseFloat(productDetails.stock_amount))) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse.transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
} }
@@ -177,11 +178,11 @@ $('#save-mark-as-open-button').on('click', function(e)
} }
); );
}); });
var sumValue = 0;
$("#location_id").on('change', function(e) $("#location_id").on('change', function(e)
{ {
var locationId = $(e.target).val(); var locationId = $(e.target).val();
var sumValue = 0; sumValue = 0;
var stockId = null; var stockId = null;
$("#specific_stock_entry").find("option").remove().end().append("<option></option>"); $("#specific_stock_entry").find("option").remove().end().append("<option></option>");
@@ -228,37 +229,8 @@ $("#location_id").on('change', function(e)
Grocy.Api.Get('stock/products/' + Grocy.Components.ProductPicker.GetValue(), Grocy.Api.Get('stock/products/' + Grocy.Components.ProductPicker.GetValue(),
function(productDetails) function(productDetails)
{ {
if (productDetails.product.enable_tare_weight_handling == 1) current_productDetails = productDetails;
{ RefreshForm();
$("#amount").attr("min", productDetails.product.tare_weight);
$('#amount').attr('max', sumValue + parseFloat(productDetails.product.tare_weight));
$("#amount").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', parseFloat(productDetails.product.tare_weight).toLocaleString(), (parseFloat(productDetails.stock_amount) + parseFloat(productDetails.product.tare_weight)).toLocaleString()));
$("#tare-weight-handling-info").removeClass("d-none");
}
else
{
$("#tare-weight-handling-info").addClass("d-none");
if (productDetails.product.allow_partial_units_in_stock == 1)
{
$("#amount").attr("min", "0.01");
$("#amount").attr("step", "0.01");
$("#amount").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', 0.01.toLocaleString(), parseFloat(productDetails.stock_amount).toLocaleString()));
}
else
{
$("#amount").attr("min", "1");
$("#amount").attr("step", "1");
$("#amount").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', "1", parseFloat(productDetails.stock_amount).toLocaleString()));
}
$('#amount').attr('max', sumValue);
if (sumValue == 0)
{
$("#amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location'));
}
}
}, },
function(xhr) function(xhr)
{ {
@@ -447,7 +419,7 @@ $("#specific_stock_entry").on("change", function(e)
{ {
if ($(e.target).val() == "") if ($(e.target).val() == "")
{ {
var sumValue = 0; sumValue = 0;
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries', Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries',
function(stockEntries) function(stockEntries)
{ {
@@ -572,3 +544,49 @@ $("#scan-mode-button").on("click", function(e)
$("#scan-mode-status").text(__t("off")); $("#scan-mode-status").text(__t("off"));
} }
}); });
$('#consume-exact-amount').on('change', RefreshForm);
var current_productDetails;
function RefreshForm()
{
var productDetails = current_productDetails;
if (productDetails.product.enable_tare_weight_handling == 1)
{
$("#consume-exact-amount").parent().removeClass("d-none");
}
else
{
$("#consume-exact-amount").parent().addClass("d-none");
}
if (productDetails.product.enable_tare_weight_handling == 1 && !$('#consume-exact-amount').is(':checked'))
{
$("#amount").attr("min", productDetails.product.tare_weight);
$('#amount').attr('max', sumValue + parseFloat(productDetails.product.tare_weight));
$("#amount").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', parseFloat(productDetails.product.tare_weight).toLocaleString(), (parseFloat(productDetails.stock_amount) + parseFloat(productDetails.product.tare_weight)).toLocaleString()));
$("#tare-weight-handling-info").removeClass("d-none");
}
else
{
$("#tare-weight-handling-info").addClass("d-none");
if (productDetails.product.allow_partial_units_in_stock == 1)
{
$("#amount").attr("min", "0.01");
$("#amount").attr("step", "0.01");
$("#amount").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', 0.01.toLocaleString(), parseFloat(productDetails.stock_amount).toLocaleString()));
}
else
{
$("#amount").attr("min", "1");
$("#amount").attr("step", "1");
$("#amount").parent().find(".invalid-feedback").text(__t('The amount must be between %1$s and %2$s', "1", parseFloat(productDetails.stock_amount).toLocaleString()));
}
$('#amount').attr('max', sumValue);
if (sumValue == 0)
{
$("#amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location'));
}
}
}

View File

@@ -1,4 +1,4 @@
function saveRecipePicture(result, location) function saveRecipePicture(result, location, jsonData)
{ {
$recipeId = Grocy.EditObjectId || result.created_object_id; $recipeId = Grocy.EditObjectId || result.created_object_id;
Grocy.Components.UserfieldsForm.Save(() => Grocy.Components.UserfieldsForm.Save(() =>
@@ -43,7 +43,7 @@ $('.save-recipe').on('click', function(e)
{ {
console.log(jsonData); console.log(jsonData);
Grocy.Api.Post('objects/recipes', jsonData, Grocy.Api.Post('objects/recipes', jsonData,
(result) => saveRecipePicture(result, location)); (result) => saveRecipePicture(result, location, jsonData));
return; return;
} }
@@ -65,7 +65,7 @@ $('.save-recipe').on('click', function(e)
} }
Grocy.Api.Put('objects/recipes/' + Grocy.EditObjectId, jsonData, Grocy.Api.Put('objects/recipes/' + Grocy.EditObjectId, jsonData,
(result) => saveRecipePicture(result, location), (result) => saveRecipePicture(result, location, jsonData),
function(xhr) function(xhr)
{ {
Grocy.FrontendHelpers.EndUiBusy("recipe-form"); Grocy.FrontendHelpers.EndUiBusy("recipe-form");

View File

@@ -139,7 +139,7 @@ if (Grocy.EditMode === "edit")
$('#amount').on('focus', function(e) $('#amount').on('focus', function(e)
{ {
if (Grocy.Components.ProductPicker.GetValue().length === 0) if (Grocy.Components.ProductPicker.GetValue().length === 0 && Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK)
{ {
Grocy.Components.ProductPicker.GetInputElement().focus(); Grocy.Components.ProductPicker.GetInputElement().focus();
} }

View File

@@ -58,7 +58,7 @@ class RecipesService extends BaseService
{ {
if ($recipePosition->only_check_single_unit_in_stock == 0) if ($recipePosition->only_check_single_unit_in_stock == 0)
{ {
$this->getStockService()->ConsumeProduct($recipePosition->product_id, $recipePosition->recipe_amount, false, StockService::TRANSACTION_TYPE_CONSUME, 'default', $recipeId, null, $transactionId, true); $this->getStockService()->ConsumeProduct($recipePosition->product_id, $recipePosition->recipe_amount, false, StockService::TRANSACTION_TYPE_CONSUME, 'default', $recipeId, null, $transactionId, true, true);
} }
} }

View File

@@ -210,7 +210,7 @@ class StockService extends BaseService
$this->getDatabase()->shopping_list()->where('shopping_list_id = :1', $listId)->delete(); $this->getDatabase()->shopping_list()->where('shopping_list_id = :1', $listId)->delete();
} }
public function ConsumeProduct(int $productId, float $amount, bool $spoiled, $transactionType, $specificStockEntryId = 'default', $recipeId = null, $locationId = null, &$transactionId = null, $allowSubproductSubstitution = false) public function ConsumeProduct(int $productId, float $amount, bool $spoiled, $transactionType, $specificStockEntryId = 'default', $recipeId = null, $locationId = null, &$transactionId = null, $allowSubproductSubstitution = false, $consumeExactAmount = false)
{ {
if (!$this->ProductExists($productId)) if (!$this->ProductExists($productId))
{ {
@@ -230,6 +230,10 @@ class StockService extends BaseService
if ($productDetails->product->enable_tare_weight_handling == 1) if ($productDetails->product->enable_tare_weight_handling == 1)
{ {
if($consumeExactAmount)
{
$amount = floatval($productDetails->stock_amount) + floatval($productDetails->product->tare_weight) - $amount;
}
if ($amount < floatval($productDetails->product->tare_weight)) if ($amount < floatval($productDetails->product->tare_weight))
{ {
throw new \Exception('The amount cannot be lower than the defined tare weight'); throw new \Exception('The amount cannot be lower than the defined tare weight');
@@ -249,6 +253,11 @@ class StockService extends BaseService
$potentialStockEntries = $this->GetProductStockEntriesForLocation($productId, $locationId, false, $allowSubproductSubstitution); $potentialStockEntries = $this->GetProductStockEntriesForLocation($productId, $locationId, false, $allowSubproductSubstitution);
} }
if ($specificStockEntryId !== 'default')
{
$potentialStockEntries = FindAllObjectsInArrayByPropertyValue($potentialStockEntries, 'stock_id', $specificStockEntryId);
}
$productStockAmount = SumArrayValue($potentialStockEntries, 'amount'); $productStockAmount = SumArrayValue($potentialStockEntries, 'amount');
if ($amount > $productStockAmount) if ($amount > $productStockAmount)
@@ -256,11 +265,6 @@ class StockService extends BaseService
throw new \Exception('Amount to be consumed cannot be > current stock amount (if supplied, at the desired location)'); throw new \Exception('Amount to be consumed cannot be > current stock amount (if supplied, at the desired location)');
} }
if ($specificStockEntryId !== 'default')
{
$potentialStockEntries = FindAllObjectsInArrayByPropertyValue($potentialStockEntries, 'stock_id', $specificStockEntryId);
}
if ($transactionId === null) if ($transactionId === null)
{ {
$transactionId = uniqid(); $transactionId = uniqid();

View File

@@ -6,9 +6,10 @@
@php if(empty($prefillById)) { $prefillById = ''; } @endphp @php if(empty($prefillById)) { $prefillById = ''; } @endphp
@php if(!isset($isRequired)) { $isRequired = true; } @endphp @php if(!isset($isRequired)) { $isRequired = true; } @endphp
@php if(empty($hint)) { $hint = ''; } @endphp @php if(empty($hint)) { $hint = ''; } @endphp
@php if(empty($nextInputSelector)) { $nextInputSelector = ''; } @endphp
<div class="form-group" <div class="form-group"
@if(isset($nextInputSelector))data-next-input-selector="{{ $nextInputSelector }}" @endif data-next-input-selector="{{ $nextInputSelector }}"
data-prefill-by-name="{{ $prefillByName }}" data-prefill-by-name="{{ $prefillByName }}"
data-prefill-by-id="{{ $prefillById }}"> data-prefill-by-id="{{ $prefillById }}">
<label for="location_id">{{ $__t('Location') }}&nbsp;&nbsp;<span @if(!empty($hintId))id="{{ $hintId }}" @endif <label for="location_id">{{ $__t('Location') }}&nbsp;&nbsp;<span @if(!empty($hintId))id="{{ $hintId }}" @endif

View File

@@ -43,7 +43,10 @@
'nextInputSelector' => '#amount', 'nextInputSelector' => '#amount',
'disallowAddProductWorkflows' => true 'disallowAddProductWorkflows' => true
)) ))
<label for="consume-exact-amount" class="d-none">
<input type="checkbox" id="consume-exact-amount" name="exact_amount">
{{ $__t('Consume exact amount') }}
</label>
@include('components.numberpicker', array( @include('components.numberpicker', array(
'id' => 'amount', 'id' => 'amount',
'label' => 'Amount', 'label' => 'Amount',

View File

@@ -3,6 +3,7 @@
@section('title', $__t('Equipment')) @section('title', $__t('Equipment'))
@section('activeNav', 'equipment') @section('activeNav', 'equipment')
@section('viewJsName', 'equipment') @section('viewJsName', 'equipment')
@section('DbChangedHandlingEnabledForPage', 'false')
@section('content') @section('content')
<div class="row"> <div class="row">

View File

@@ -82,7 +82,7 @@
@if(file_exists(GROCY_DATAPATH . '/custom_css.html')) @if(file_exists(GROCY_DATAPATH . '/custom_css.html'))
@php include GROCY_DATAPATH . '/custom_css.html' @endphp @php include GROCY_DATAPATH . '/custom_css.html' @endphp
@endif @endif
@section('DbChangedHandlingEnabledForPage', 'true')
<script> <script>
var Grocy = { }; var Grocy = { };
Grocy.Components = { }; Grocy.Components = { };
@@ -96,6 +96,7 @@
Grocy.CalendarShowWeekNumbers = {{ BoolToString(GROCY_CALENDAR_SHOW_WEEK_OF_YEAR) }}; Grocy.CalendarShowWeekNumbers = {{ BoolToString(GROCY_CALENDAR_SHOW_WEEK_OF_YEAR) }};
Grocy.GettextPo = {!! $GettextPo !!}; Grocy.GettextPo = {!! $GettextPo !!};
Grocy.FeatureFlags = {!! json_encode($featureFlags) !!}; Grocy.FeatureFlags = {!! json_encode($featureFlags) !!};
Grocy.DbChangedHandlingEnabledForPage = @yield('DbChangedHandlingEnabledForPage');
@if (GROCY_AUTHENTICATED) @if (GROCY_AUTHENTICATED)
Grocy.UserSettings = {!! json_encode($userSettings) !!}; Grocy.UserSettings = {!! json_encode($userSettings) !!};

View File

@@ -50,7 +50,7 @@
<span class="input-group-text"><i class="fas fa-filter"></i></span> <span class="input-group-text"><i class="fas fa-filter"></i></span>
</div> </div>
<select class="form-control" <select class="form-control"
id="location-filter"> id="product-group-filter">
<option value="all">{{ $__t('All') }}</option> <option value="all">{{ $__t('All') }}</option>
@foreach($productGroups as $productGroup) @foreach($productGroups as $productGroup)
<option value="{{ $productGroup->id }}">{{ $productGroup->name }}</option> <option value="{{ $productGroup->id }}">{{ $productGroup->name }}</option>

View File

@@ -71,7 +71,7 @@
</div> </div>
<hr> <hr>
<p data-status-filter="belowminstockamount" <p data-status-filter="belowminstockamount"
class="normal-message status-filter-message responsive-button">{{ $__n(count($missingProducts), '%s product is below defined min. stock amount', '%s products are below defined min. stock amount') }}</p> class="normal-message status-filter-message responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif">{{ $__n(count($missingProducts), '%s product is below defined min. stock amount', '%s products are below defined min. stock amount') }}</p>
</div> </div>
</div> </div>
@@ -87,17 +87,17 @@
{{ $__t('Clear list') }} {{ $__t('Clear list') }}
</a> </a>
<a id="add-all-items-to-stock-button" <a id="add-all-items-to-stock-button"
class="btn btn-outline-primary btn-sm mb-1 responsive-button" class="btn btn-outline-primary btn-sm mb-1 responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
href="#"> href="#">
{{ $__t('Add all list items to stock') }} {{ $__t('Add all list items to stock') }}
</a> </a>
<a id="add-products-below-min-stock-amount" <a id="add-products-below-min-stock-amount"
class="btn btn-outline-primary btn-sm mb-1 responsive-button" class="btn btn-outline-primary btn-sm mb-1 responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
href="#"> href="#">
{{ $__t('Add products that are below defined min. stock amount') }} {{ $__t('Add products that are below defined min. stock amount') }}
</a> </a>
<a id="add-expired-products" <a id="add-expired-products"
class="btn btn-outline-primary btn-sm mb-1 responsive-button" class="btn btn-outline-primary btn-sm mb-1 responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
href="#"> href="#">
{{ $__t('Add expired products') }} {{ $__t('Add expired products') }}
</a> </a>
@@ -121,7 +121,7 @@
<select class="form-control" <select class="form-control"
id="status-filter"> id="status-filter">
<option value="all">{{ $__t('All') }}</option> <option value="all">{{ $__t('All') }}</option>
<option value="belowminstockamount">{{ $__t('Below min. stock amount') }}</option> <option class="@if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif" value="belowminstockamount">{{ $__t('Below min. stock amount') }}</option>
<option value="xxUNDONExx">{{ $__t('Only undone items') }}</option> <option value="xxUNDONExx">{{ $__t('Only undone items') }}</option>
</select> </select>
</div> </div>
@@ -188,7 +188,7 @@
title="{{ $__t('Delete this item') }}"> title="{{ $__t('Delete this item') }}">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
</a> </a>
<a class="btn btn-sm btn-primary @if(empty($listItem->product_id)) disabled @else shopping-list-stock-add-workflow-list-item-button @endif" <a class="btn btn-sm btn-primary @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif @if(empty($listItem->product_id)) disabled @else shopping-list-stock-add-workflow-list-item-button @endif"
href="{{ $U('/purchase?embedded&flow=shoppinglistitemtostock&product=') }}{{ $listItem->product_id }}&amount={{ $listItem->amount }}&listitemid={{ $listItem->id }}" href="{{ $U('/purchase?embedded&flow=shoppinglistitemtostock&product=') }}{{ $listItem->product_id }}&amount={{ $listItem->amount }}&listitemid={{ $listItem->id }}"
@if(!empty($listItem->product_id)) data-toggle="tooltip" title="{{ $__t('Add %1$s of %2$s to stock', $listItem->amount . ' ' . $__n($listItem->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->qu_id_purchase)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->qu_id_purchase)->name_plural), FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->name, $listItem->amount) }}" @endif> @if(!empty($listItem->product_id)) data-toggle="tooltip" title="{{ $__t('Add %1$s of %2$s to stock', $listItem->amount . ' ' . $__n($listItem->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->qu_id_purchase)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->qu_id_purchase)->name_plural), FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->name, $listItem->amount) }}" @endif>
<i class="fas fa-box"></i> <i class="fas fa-box"></i>

View File

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