mirror of
https://github.com/grocy/grocy.git
synced 2025-04-29 01:32:38 +00:00
Implemented stock sub-feature-flags (closes #314)
This commit is contained in:
parent
5e9a7fb7ca
commit
cbf1d1ca40
@ -7,7 +7,7 @@
|
||||
- Available on any barcode-enabled field (so currently only for picking products) - a new camera button at the right of side the text field
|
||||
- Implemented using [QuaggaJS](https://github.com/serratus/quaggaJS) - camera stream processing happens totally offline / client-side
|
||||
- Please note due to browser security restrictions, this only works when serving grocy via a secure connection (`https://`)
|
||||
- There is also a `config.php` setting `DISABLE_BROWSER_BARCODE_CAMERA_SCANNING` to disable this, if you don't need it at all
|
||||
- There is also a `config.php` setting `DISABLE_BROWSER_BARCODE_CAMERA_SCANNING` to disable this, if you don't need it at all (defaults to `false`)
|
||||
|
||||
### Stock improvements
|
||||
- Products can now have variations (nested products)
|
||||
@ -21,6 +21,11 @@
|
||||
- It's now possible to print a "Location Content Sheet" with the current stock per location - new button at the top of the stock overview page (thought to hang it at the location, note used amounts on paper and track it in grocy later)
|
||||
- The product description now can have formattings (HTML/WYSIWYG editor like for recipes)
|
||||
- "Factor purchase to stock quantity unit" (product option) can now also be a decimal number when "Allow partial units in stock" is enabled
|
||||
- New "Sub feature flags" in `config.php` to disable some sub-features (hide the corresponding UI elements) if you don't need them (all new feature flags default to `true`, so no changed behaviour when not configured)
|
||||
- `FEATURE_FLAG_STOCK_PRICE_TRACKING` to disable product price tracking
|
||||
- `FEATURE_FLAG_STOCK_LOCATION_TRACKING` to disable product location tracking
|
||||
- `FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING` to disable product best before date tracking
|
||||
- `FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING` to disable product opened tracking
|
||||
|
||||
### Recipe improvements
|
||||
- Based on the new linked quantity units, recipe ingredients can now use any product related unit, the amount is calculated according to the cnoversion factor of the unit relation
|
||||
|
@ -17,8 +17,8 @@
|
||||
# Either "production", "dev" or "prerelease"
|
||||
Setting('MODE', 'production');
|
||||
|
||||
# Either "en" or "de" or the filename (without extension) of
|
||||
# one of the other available localization files in the "/localization" directory
|
||||
# Either "en" or "de" or the directory name of
|
||||
# one of the other available localization folders in the "/localization" directory
|
||||
Setting('CULTURE', 'en');
|
||||
|
||||
# This is used to define the first day of a week for calendar views in the frontend,
|
||||
@ -45,12 +45,11 @@ Setting('BASE_URL', '/');
|
||||
# see /data/plugins/DemoBarcodeLookupPlugin.php for an example implementation
|
||||
Setting('STOCK_BARCODE_LOOKUP_PLUGIN', 'DemoBarcodeLookupPlugin');
|
||||
|
||||
# If, however, your webserver does not support URL rewriting,
|
||||
# set this to true
|
||||
# If, however, your webserver does not support URL rewriting, set this to true
|
||||
Setting('DISABLE_URL_REWRITING', false);
|
||||
|
||||
# Specify an custom homepage if desired. By default the homepage will be set to the stock overview.
|
||||
# You can chosen one of the following values:
|
||||
# Specify an custom homepage if desired - by default the homepage will be set to the stock overview,
|
||||
# this needs to be one of the following values:
|
||||
# stock, shoppinglist, recipes, chores, tasks, batteries, equipment, calendar
|
||||
Setting('ENTRY_PAGE', 'stock');
|
||||
|
||||
@ -61,6 +60,7 @@ Setting('DISABLE_AUTH', false);
|
||||
# Set this to true if you want to disable the ability to scan a barcode via the device camera (Browser API)
|
||||
Setting('DISABLE_BROWSER_BARCODE_CAMERA_SCANNING', false);
|
||||
|
||||
|
||||
# Default user settings
|
||||
# These settings can be changed per user, here the defaults
|
||||
# are defined which are used when the user has not changed the setting so far
|
||||
@ -103,8 +103,6 @@ DefaultUserSetting('show_clock_in_header', false);
|
||||
DefaultUserSetting('shopping_list_to_stock_workflow_auto_submit_when_prefilled', false);
|
||||
|
||||
|
||||
|
||||
|
||||
# Feature flags
|
||||
# grocy was initially about "stock management for your household", many other things
|
||||
# came and still come by, because they are useful - here you can disable the parts
|
||||
@ -118,3 +116,9 @@ Setting('FEATURE_FLAG_TASKS', true);
|
||||
Setting('FEATURE_FLAG_BATTERIES', true);
|
||||
Setting('FEATURE_FLAG_EQUIPMENT', true);
|
||||
Setting('FEATURE_FLAG_CALENDAR', true);
|
||||
|
||||
# Sub feature flags
|
||||
Setting('FEATURE_FLAG_STOCK_PRICE_TRACKING', true);
|
||||
Setting('FEATURE_FLAG_STOCK_LOCATION_TRACKING', true);
|
||||
Setting('FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING', true);
|
||||
Setting('FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING', true);
|
||||
|
@ -100,35 +100,38 @@ Grocy.Components.ProductCard.Refresh = function(productId)
|
||||
}
|
||||
);
|
||||
|
||||
Grocy.Api.Get('stock/products/' + productId + '/price-history',
|
||||
function(priceHistoryDataPoints)
|
||||
{
|
||||
if (priceHistoryDataPoints.length > 0)
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||
{
|
||||
Grocy.Api.Get('stock/products/' + productId + '/price-history',
|
||||
function(priceHistoryDataPoints)
|
||||
{
|
||||
$("#productcard-product-price-history-chart").removeClass("d-none");
|
||||
$("#productcard-no-price-data-hint").addClass("d-none");
|
||||
|
||||
Grocy.Components.ProductCard.ReInitPriceHistoryChart();
|
||||
priceHistoryDataPoints.forEach((dataPoint) =>
|
||||
if (priceHistoryDataPoints.length > 0)
|
||||
{
|
||||
Grocy.Components.ProductCard.PriceHistoryChart.data.labels.push(moment(dataPoint.date).toDate());
|
||||
$("#productcard-product-price-history-chart").removeClass("d-none");
|
||||
$("#productcard-no-price-data-hint").addClass("d-none");
|
||||
|
||||
var dataset = Grocy.Components.ProductCard.PriceHistoryChart.data.datasets[0];
|
||||
dataset.data.push(dataPoint.price);
|
||||
});
|
||||
Grocy.Components.ProductCard.PriceHistoryChart.update();
|
||||
}
|
||||
else
|
||||
Grocy.Components.ProductCard.ReInitPriceHistoryChart();
|
||||
priceHistoryDataPoints.forEach((dataPoint) =>
|
||||
{
|
||||
Grocy.Components.ProductCard.PriceHistoryChart.data.labels.push(moment(dataPoint.date).toDate());
|
||||
|
||||
var dataset = Grocy.Components.ProductCard.PriceHistoryChart.data.datasets[0];
|
||||
dataset.data.push(dataPoint.price);
|
||||
});
|
||||
Grocy.Components.ProductCard.PriceHistoryChart.update();
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#productcard-product-price-history-chart").addClass("d-none");
|
||||
$("#productcard-no-price-data-hint").removeClass("d-none");
|
||||
}
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
$("#productcard-product-price-history-chart").addClass("d-none");
|
||||
$("#productcard-no-price-data-hint").removeClass("d-none");
|
||||
console.error(xhr);
|
||||
}
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
console.error(xhr);
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Grocy.Components.ProductCard.ReInitPriceHistoryChart = function()
|
||||
|
@ -17,7 +17,14 @@
|
||||
var jsonData = { };
|
||||
jsonData.new_amount = jsonForm.new_amount;
|
||||
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
||||
jsonData.location_id = Grocy.Components.LocationPicker.GetValue();
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
{
|
||||
jsonData.location_id = Grocy.Components.LocationPicker.GetValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
jsonData.location_id = 1;
|
||||
}
|
||||
jsonData.price = price;
|
||||
|
||||
Grocy.Api.Post('stock/products/' + jsonForm.product_id + '/inventory', jsonData,
|
||||
@ -120,7 +127,10 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||
}
|
||||
|
||||
$('#price').val(productDetails.last_price);
|
||||
Grocy.Components.LocationPicker.SetId(productDetails.location.id);
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
{
|
||||
Grocy.Components.LocationPicker.SetId(productDetails.location.id);
|
||||
}
|
||||
$('#new_amount').focus();
|
||||
},
|
||||
function(xhr)
|
||||
@ -221,13 +231,24 @@ $('#new_amount').on('keyup', function(e)
|
||||
{
|
||||
$('#inventory-change-info').text(__t('This means %s will be added to stock', estimatedBookingAmount.toLocaleString() + ' ' + __n(estimatedBookingAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural)));
|
||||
Grocy.Components.DateTimePicker.GetInputElement().attr('required', '');
|
||||
Grocy.Components.LocationPicker.GetInputElement().attr('required', '');
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
{
|
||||
Grocy.Components.LocationPicker.GetInputElement().attr('required', '');
|
||||
}
|
||||
}
|
||||
else if (newAmount < productStockAmount + containerWeight)
|
||||
{
|
||||
$('#inventory-change-info').text(__t('This means %s will be removed from stock', estimatedBookingAmount.toLocaleString() + ' ' + __n(estimatedBookingAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural)));
|
||||
Grocy.Components.DateTimePicker.GetInputElement().removeAttr('required');
|
||||
Grocy.Components.LocationPicker.GetInputElement().removeAttr('required');
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
{
|
||||
Grocy.Components.LocationPicker.GetInputElement().removeAttr('required');
|
||||
}
|
||||
}
|
||||
|
||||
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||
{
|
||||
Grocy.Components.DateTimePicker.GetInputElement().removeAttr('required');
|
||||
}
|
||||
|
||||
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
||||
|
@ -20,7 +20,14 @@
|
||||
jsonData.amount = amount;
|
||||
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
||||
jsonData.price = price;
|
||||
jsonData.location_id = Grocy.Components.LocationPicker.GetValue();
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
{
|
||||
jsonData.location_id = Grocy.Components.LocationPicker.GetValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
jsonData.location_id = 1;
|
||||
}
|
||||
|
||||
Grocy.Api.Post('stock/products/' + jsonForm.product_id + '/add', jsonData,
|
||||
function(result)
|
||||
@ -73,7 +80,10 @@
|
||||
$('#price').val('');
|
||||
$('#amount_qu_unit').text("");
|
||||
$("#tare-weight-handling-info").addClass("d-none");
|
||||
Grocy.Components.LocationPicker.Clear();
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
{
|
||||
Grocy.Components.LocationPicker.Clear();
|
||||
}
|
||||
Grocy.Components.DateTimePicker.Clear();
|
||||
Grocy.Components.ProductPicker.SetValue('');
|
||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
||||
@ -107,7 +117,10 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||
function (productDetails)
|
||||
{
|
||||
$('#price').val(productDetails.last_price);
|
||||
Grocy.Components.LocationPicker.SetId(productDetails.location.id);
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
{
|
||||
Grocy.Components.LocationPicker.SetId(productDetails.location.id);
|
||||
}
|
||||
|
||||
if (productDetails.product.qu_id_purchase === productDetails.product.qu_id_stock)
|
||||
{
|
||||
@ -166,7 +179,15 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||
}
|
||||
else
|
||||
{
|
||||
Grocy.Components.DateTimePicker.GetInputElement().focus();
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||
{
|
||||
Grocy.Components.DateTimePicker.GetInputElement().focus();
|
||||
}
|
||||
else
|
||||
{
|
||||
Grocy.Components.DateTimePicker.SetValue(moment().format('YYYY-MM-DD'));
|
||||
$('#amount').focus();
|
||||
}
|
||||
}
|
||||
},
|
||||
function(xhr)
|
||||
|
@ -13,8 +13,9 @@
|
||||
@php if(!isset($noNameAttribute)) { $noNameAttribute = false; } @endphp
|
||||
@php if(!isset($nextInputSelector)) { $nextInputSelector = false; } @endphp
|
||||
@php if(empty($additionalAttributes)) { $additionalAttributes = ''; } @endphp
|
||||
@php if(empty($additionalGroupCssClasses)) { $additionalGroupCssClasses = ''; } @endphp
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group {{ $additionalGroupCssClasses }}">
|
||||
<label for="{{ $id }}">{{ $__t($label) }}
|
||||
<span class="small text-muted">
|
||||
@if(!empty($hint)){{ $__t($hint) }}@endif
|
||||
|
@ -20,19 +20,21 @@
|
||||
|
||||
<strong>{{ $__t('Stock amount') . ' / ' . $__t('Quantity unit') }}:</strong> <span id="productcard-product-stock-amount"></span> <span id="productcard-product-stock-qu-name"></span> <span id="productcard-product-stock-opened-amount" class="small font-italic"></span>
|
||||
<span id="productcard-aggregated-amounts" class="pl-2 text-secondary d-none"><i class="fas fa-custom-sigma-sign"></i> <span id="productcard-product-stock-amount-aggregated"></span> <span id="productcard-product-stock-qu-name-aggregated"></span> <span id="productcard-product-stock-opened-amount-aggregated" class="small font-italic"></span></span><br>
|
||||
<strong>{{ $__t('Location') }}:</strong> <span id="productcard-product-location"></span><br>
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)<strong>{{ $__t('Location') }}:</strong> <span id="productcard-product-location"></span><br>@endif
|
||||
<strong>{{ $__t('Last purchased') }}:</strong> <span id="productcard-product-last-purchased"></span> <time id="productcard-product-last-purchased-timeago" class="timeago timeago-contextual"></time><br>
|
||||
<strong>{{ $__t('Last used') }}:</strong> <span id="productcard-product-last-used"></span> <time id="productcard-product-last-used-timeago" class="timeago timeago-contextual"></time><br>
|
||||
<strong>{{ $__t('Last price') }}:</strong> <span id="productcard-product-last-price"></span><br>
|
||||
<strong>{{ $__t('Average shelf life') }}:</strong> <span id="productcard-product-average-shelf-life"></span><br>
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)<strong>{{ $__t('Last price') }}:</strong> <span id="productcard-product-last-price"></span><br>@endif
|
||||
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)<strong>{{ $__t('Average shelf life') }}:</strong> <span id="productcard-product-average-shelf-life"></span><br>@endif
|
||||
<strong>{{ $__t('Spoil rate') }}:</strong> <span id="productcard-product-spoil-rate"></span>
|
||||
|
||||
<h5 class="mt-3">{{ $__t('Product picture') }}</h5>
|
||||
<p class="w-75 mx-auto"><img id="productcard-product-picture" data-src="" class="img-fluid img-thumbnail d-none lazy"></p>
|
||||
<span id="productcard-no-product-picture" class="font-italic d-none">{{ $__t('No picture available') }}</span>
|
||||
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||
<h5 class="mt-3">{{ $__t('Price history') }}</h5>
|
||||
<canvas id="productcard-product-price-history-chart" class="w-100 d-none"></canvas>
|
||||
<span id="productcard-no-price-data-hint" class="font-italic d-none">{{ $__t('No price history available') }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
@ -52,7 +52,10 @@
|
||||
@endif
|
||||
|
||||
<button id="save-consume-button" class="btn btn-success">{{ $__t('OK') }}</button>
|
||||
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
||||
<button id="save-mark-as-open-button" class="btn btn-secondary">{{ $__t('Mark as opened') }}</button>
|
||||
@endif
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
@ -28,6 +28,13 @@
|
||||
'additionalHtmlContextHelp' => '<div id="tare-weight-handling-info" class="text-small text-info font-italic d-none">' . $__t('Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated') . '</div>'
|
||||
))
|
||||
|
||||
@php
|
||||
$additionalGroupCssClasses = '';
|
||||
if (!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||
{
|
||||
$additionalGroupCssClasses = 'd-none';
|
||||
}
|
||||
@endphp
|
||||
@include('components.datetimepicker', array(
|
||||
'id' => 'best_before_date',
|
||||
'label' => 'Best before',
|
||||
@ -42,9 +49,12 @@
|
||||
'shortcutValue' => '2999-12-31',
|
||||
'shortcutLabel' => 'Never expires',
|
||||
'earlierThanInfoLimit' => date('Y-m-d'),
|
||||
'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?')
|
||||
'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'),
|
||||
'additionalGroupCssClasses' => $additionalGroupCssClasses
|
||||
))
|
||||
@php $additionalGroupCssClasses = ''; @endphp
|
||||
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||
@include('components.numberpicker', array(
|
||||
'id' => 'price',
|
||||
'label' => 'Price',
|
||||
@ -56,11 +66,18 @@
|
||||
'invalidFeedback' => $__t('The price cannot be lower than %s', '0'),
|
||||
'isRequired' => false
|
||||
))
|
||||
@else
|
||||
<input type="hidden" name="price" id="price" value="0">
|
||||
@endif
|
||||
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
@include('components.locationpicker', array(
|
||||
'locations' => $locations,
|
||||
'hint' => $__t('This will apply to added products')
|
||||
))
|
||||
@else
|
||||
<input type="hidden" name="location_id" id="location_id" value="1">
|
||||
@endif
|
||||
|
||||
<button id="save-inventory-button" class="btn btn-success">{{ $__t('OK') }}</button>
|
||||
|
||||
|
@ -212,12 +212,14 @@
|
||||
<span class="nav-link-text">{{ $__t('Products') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
<li data-nav-for-page="locations" data-sub-menu-of="#top-nav-manager-master-data">
|
||||
<a class="nav-link discrete-link" href="{{ $U('/locations') }}">
|
||||
<i class="fas fa-map-marker-alt"></i>
|
||||
<span class="nav-link-text">{{ $__t('Locations') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
<li data-nav-for-page="quantityunits" data-sub-menu-of="#top-nav-manager-master-data">
|
||||
<a class="nav-link discrete-link" href="{{ $U('/quantityunits') }}">
|
||||
<i class="fas fa-balance-scale"></i>
|
||||
|
@ -73,6 +73,7 @@
|
||||
<div id="barcode-taginput-container"></div>
|
||||
</div>
|
||||
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
<div class="form-group">
|
||||
<label for="location_id">{{ $__t('Location') }}</label>
|
||||
<select required class="form-control" id="location_id" name="location_id">
|
||||
@ -83,6 +84,9 @@
|
||||
</select>
|
||||
<div class="invalid-feedback">{{ $__t('A location is required') }}</div>
|
||||
</div>
|
||||
@else
|
||||
<input type="hidden" name="location_id" id="location_id" value="1">
|
||||
@endif
|
||||
|
||||
@php if($mode == 'edit') { $value = $product->min_stock_amount; } else { $value = 0; } @endphp
|
||||
@include('components.numberpicker', array(
|
||||
|
@ -45,7 +45,7 @@
|
||||
<tr>
|
||||
<th class="border-right"></th>
|
||||
<th>{{ $__t('Name') }}</th>
|
||||
<th>{{ $__t('Location') }}</th>
|
||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif">{{ $__t('Location') }}</th>
|
||||
<th>{{ $__t('Min. stock amount') }}</th>
|
||||
<th>{{ $__t('QU purchase') }}</th>
|
||||
<th>{{ $__t('QU stock') }}</th>
|
||||
@ -73,7 +73,7 @@
|
||||
<td>
|
||||
{{ $product->name }}@if(!empty($product->picture_file_name)) <i class="fas fa-image text-muted"></i>@endif
|
||||
</td>
|
||||
<td>
|
||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif">
|
||||
{{ FindObjectInArrayByPropertyValue($locations, 'id', $product->location_id)->name }}
|
||||
</td>
|
||||
<td>
|
||||
|
@ -16,6 +16,13 @@
|
||||
'nextInputSelector' => '#best_before_date .datetimepicker-input'
|
||||
))
|
||||
|
||||
@php
|
||||
$additionalGroupCssClasses = '';
|
||||
if (!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||
{
|
||||
$additionalGroupCssClasses = 'd-none';
|
||||
}
|
||||
@endphp
|
||||
@include('components.datetimepicker', array(
|
||||
'id' => 'best_before_date',
|
||||
'label' => 'Best before',
|
||||
@ -29,8 +36,10 @@
|
||||
'shortcutValue' => '2999-12-31',
|
||||
'shortcutLabel' => 'Never expires',
|
||||
'earlierThanInfoLimit' => date('Y-m-d'),
|
||||
'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?')
|
||||
'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'),
|
||||
'additionalGroupCssClasses' => $additionalGroupCssClasses
|
||||
))
|
||||
@php $additionalGroupCssClasses = ''; @endphp
|
||||
|
||||
@include('components.numberpicker', array(
|
||||
'id' => 'amount',
|
||||
@ -41,6 +50,7 @@
|
||||
'additionalHtmlContextHelp' => '<div id="tare-weight-handling-info" class="text-info font-italic d-none">' . $__t('Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated') . '</div>'
|
||||
))
|
||||
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||
@include('components.numberpicker', array(
|
||||
'id' => 'price',
|
||||
'label' => 'Price',
|
||||
@ -51,11 +61,18 @@
|
||||
'invalidFeedback' => $__t('The price cannot be lower than %s', '0'),
|
||||
'isRequired' => false
|
||||
))
|
||||
@else
|
||||
<input type="hidden" name="price" id="price" value="0">
|
||||
@endif
|
||||
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
@include('components.locationpicker', array(
|
||||
'locations' => $locations,
|
||||
'isRequired' => false
|
||||
))
|
||||
@else
|
||||
<input type="hidden" name="location_id" id="location_id" value="1">
|
||||
@endif
|
||||
|
||||
<button id="save-purchase-button" class="btn btn-success">{{ $__t('OK') }}</button>
|
||||
|
||||
|
@ -155,6 +155,7 @@
|
||||
'additionalAttributes' => 'data-recipe-id="' . $selectedRecipe->id . '"'
|
||||
))
|
||||
</div>
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||
<div class="col-7">
|
||||
<label>{{ $__t('Costs') }}
|
||||
<span class="small text-muted">{{ $__t('Based on the prices of the last purchase per product') }}</span>
|
||||
@ -163,6 +164,7 @@
|
||||
<span class="locale-number-format" data-format="currency">{{ $selectedRecipeTotalCosts }}</span>
|
||||
</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -24,12 +24,16 @@
|
||||
<a class="btn btn-outline-dark responsive-button" href="{{ $U('/stockjournal') }}">
|
||||
<i class="fas fa-file-alt"></i> {{ $__t('Journal') }}
|
||||
</a>
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
<a class="btn btn-outline-dark responsive-button" href="{{ $U('/locationcontentsheet') }}">
|
||||
<i class="fas fa-print"></i> {{ $__t('Location Content Sheet') }}
|
||||
</a>
|
||||
@endif
|
||||
</h1>
|
||||
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||
<p id="info-expiring-products" data-next-x-days="{{ $nextXDays }}" data-status-filter="expiring" class="btn btn-lg btn-warning status-filter-button responsive-button mr-2"></p>
|
||||
<p id="info-expired-products" data-status-filter="expired" class="btn btn-lg btn-danger status-filter-button responsive-button mr-2"></p>
|
||||
@endif
|
||||
<p id="info-missing-products" data-status-filter="belowminstockamount" class="btn btn-lg btn-info status-filter-button responsive-button"></p>
|
||||
</div>
|
||||
</div>
|
||||
@ -39,6 +43,7 @@
|
||||
<label for="search">{{ $__t('Search') }}</label> <i class="fas fa-search"></i>
|
||||
<input type="text" class="form-control" id="search">
|
||||
</div>
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
<div class="col-xs-12 col-md-6 col-xl-3">
|
||||
<label for="location-filter">{{ $__t('Filter by location') }}</label> <i class="fas fa-filter"></i>
|
||||
<select class="form-control" id="location-filter">
|
||||
@ -48,6 +53,7 @@
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
@endif
|
||||
<div class="col-xs-12 col-md-6 col-xl-3">
|
||||
<label for="location-filter">{{ $__t('Filter by product group') }}</label> <i class="fas fa-filter"></i>
|
||||
<select class="form-control" id="product-group-filter">
|
||||
@ -61,8 +67,10 @@
|
||||
<label for="status-filter">{{ $__t('Filter by status') }}</label> <i class="fas fa-filter"></i>
|
||||
<select class="form-control" id="status-filter">
|
||||
<option class="bg-white" value="all">{{ $__t('All') }}</option>
|
||||
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||
<option class="bg-warning" value="expiring">{{ $__t('Expiring soon') }}</option>
|
||||
<option class="bg-danger" value="expired">{{ $__t('Already expired') }}</option>
|
||||
@endif
|
||||
<option class="bg-info" value="belowminstockamount">{{ $__t('Below min. stock amount') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
@ -89,7 +97,7 @@
|
||||
</thead>
|
||||
<tbody class="d-none">
|
||||
@foreach($currentStock as $currentStockEntry)
|
||||
<tr id="product-{{ $currentStockEntry->product_id }}-row" class="@if($currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('-1 days')) && $currentStockEntry->amount > 0) table-danger @elseif($currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime("+$nextXDays days")) && $currentStockEntry->amount > 0) table-warning @elseif (FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) table-info @endif">
|
||||
<tr id="product-{{ $currentStockEntry->product_id }}-row" class="@if(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && $currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('-1 days')) && $currentStockEntry->amount > 0) table-danger @elseif(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && $currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime("+$nextXDays days")) && $currentStockEntry->amount > 0) table-warning @elseif (FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) table-info @endif">
|
||||
<td class="fit-content border-right">
|
||||
<a class="btn btn-success btn-sm product-consume-button @if($currentStockEntry->amount < 1) disabled @endif" href="#" data-toggle="tooltip" data-placement="left" title="{{ $__t('Consume %1$s of %2$s', '1 ' . FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name) }}"
|
||||
data-product-id="{{ $currentStockEntry->product_id }}"
|
||||
@ -105,12 +113,14 @@
|
||||
data-consume-amount="{{ $currentStockEntry->amount }}">
|
||||
<i class="fas fa-utensils"></i> {{ $__t('All') }}
|
||||
</a>
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
||||
<a class="btn btn-success btn-sm product-open-button @if($currentStockEntry->amount < 1 || $currentStockEntry->amount == $currentStockEntry->amount_opened) disabled @endif" href="#" data-toggle="tooltip" data-placement="left" title="{{ $__t('Mark %1$s of %2$s as open', '1 ' . FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name) }}"
|
||||
data-product-id="{{ $currentStockEntry->product_id }}"
|
||||
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name }}"
|
||||
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name }}">
|
||||
<i class="fas fa-box-open"></i> 1
|
||||
</a>
|
||||
@endif
|
||||
<div class="dropdown d-inline-block">
|
||||
<button class="btn btn-sm btn-light text-secondary" type="button" data-toggle="dropdown">
|
||||
<i class="fas fa-ellipsis-v"></i>
|
||||
|
@ -12,6 +12,7 @@
|
||||
<div id="productpresets">
|
||||
<h4>{{ $__t('Presets for new products') }}</h4>
|
||||
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
<div class="form-group">
|
||||
<label for="product_presets_location_id">{{ $__t('Location') }}</label>
|
||||
<select class="form-control user-setting-control" id="product_presets_location_id" data-setting-key="product_presets_location_id">
|
||||
@ -21,6 +22,7 @@
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="form-group">
|
||||
<label for="product_presets_product_group_id">{{ $__t('Product group') }}</label>
|
||||
|
Loading…
x
Reference in New Issue
Block a user