Qu factor purchase to stock & Product Barcode Details (#801)

* Puchase add qu_factor_to_stock

* qu_factor_purchase_to_stock for stock edit

* product barcodes with QU and Stores

* remove product barcode tags

* migrations/0103 add value and factor_puchase_amount to stock_current and stock_current_location_content

* Remove unused method

* StockService#GetProductDetails: include stock_value

* productcard: include stock_value

* Add Purchase Factor to Stock Overview

* update demo data with stock qu_factor_purchase_to_stock

* recipes_pos_resolved update

* avg_price and oldest_price in product details

* add average price to product card

* hint for recipe costs not included if not in stock

* Round value and factor_purchas_amount. Include currency for stock value

* Add factor_purchase_amount to product card stock amount

* Allow editing qu_factor_purchase_to_stock for stock entries

* fix update qu_factor_purchase_to_stock for Transfers

* Add barcode to existing product update to add to product_barcodes table

* Add barcode to new product workflow update to add to product_barcodes table

* *** Price now saved as 1 QU to stock in stock tables ***

* remove column product barcode and use product_barcodes

* Allow products to be deactivated instead of deleted

* Embedded barcode and qu-conversion with page reload on change

* Save current product barcode into new product_barcodes table

* Embedded popup for product group add/edit

* barcode scanner added to product barcodes input

* Edit product qu_stock is unavailable after first purchase

* StockOverview: Filters break when columns are reordered so for now just disable colReorder

* view stockoverview.blade: display product_group column

* Review

Co-authored-by: Bernd Bestel <bernd@berrnd.de>
This commit is contained in:
kriddles
2020-08-17 14:47:33 -05:00
committed by GitHub
parent d1e395b45e
commit e8845fe2e8
40 changed files with 1216 additions and 266 deletions

View File

@@ -16,7 +16,7 @@
@php if(!isset($isRequired)) { $isRequired = true; } @endphp
@php if(!isset($noNameAttribute)) { $noNameAttribute = false; } @endphp
<div class="form-group {{ $additionalGroupCssClasses }}">
<div id="group-{{ $id }}" class="form-group {{ $additionalGroupCssClasses }}">
<label for="{{ $id }}">
{{ $__t($label) }}&nbsp;
<i class="fas fa-question-circle" id="{{ $hintId }}" data-toggle="tooltip" title="{{ $hint }}"></i>{!! $additionalHtmlContextHelp !!}</label>

View File

@@ -21,12 +21,16 @@
<a class="collapsed" data-toggle="collapse" href="#productcard-product-description">{{ $__t('Show more') }}</a>
</div>
<strong>{{ $__t('Stock amount') . ' / ' . $__t('Quantity unit') }}:</strong> <span id="productcard-product-stock-amount" class="locale-number locale-number-quantity-amount"></span> <span id="productcard-product-stock-qu-name"></span> <span id="productcard-product-stock-opened-amount" class="small font-italic locale-number locale-number-quantity-amount"></span>
<strong>{{ $__t('Stock amount') }}:</strong> <span id="productcard-product-stock-amount" class="locale-number locale-number-quantity-amount"></span> <span id="productcard-product-stock-qu-name"></span>
<span id="productcard-product-stock-factor-purchase-amount" class="locale-number locale-number-quantity-amount"></span> <span id="productcard-product-stock-factor-purchase-qu-name"></span>
<span id="productcard-product-stock-opened-amount" class="small font-italic locale-number locale-number-quantity-amount"></span><br>
<strong>{{ $__t('Stock value') }}:</strong> <span id="productcard-product-stock-value" class="locale-number locale-number-currency"></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" class="locale-number locale-number-quantity-amount"></span> <span id="productcard-product-stock-qu-name-aggregated"></span> <span id="productcard-product-stock-opened-amount-aggregated locale-number locale-number-quantity-amount" class="small font-italic"></span></span><br>
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)<strong>{{ $__t('Default 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>
@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_PRICE_TRACKING)<strong>{{ $__t('Average price') }}:</strong> <span id="productcard-product-average-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>

View File

@@ -21,7 +21,7 @@
<select class="form-control product-combobox barcodescanner-input" id="product_id" name="product_id" @if($isRequired) required @endif @if($disabled) disabled @endif data-target="@productpicker">
<option value=""></option>
@foreach($products as $product)
<option data-additional-searchdata="{{ $product->barcode }}@if(!empty($product->barcode)),@endif" value="{{ $product->id }}">{{ $product->name }}</option>
<option data-additional-searchdata="{{ FindObjectInArrayByPropertyValue($barcodes, 'product_id', $product->id)->barcodes }}," value="{{ $product->id }}">{{ $product->name }}</option>
@endforeach
</select>
<div class="invalid-feedback">{{ $__t('You have to select a product') }}</div>

View File

@@ -30,6 +30,7 @@
@include('components.productpicker', array(
'products' => $products,
'barcodes' => $barcodes,
'nextInputSelector' => '#amount',
'disallowAddProductWorkflows' => true
))

View File

@@ -13,6 +13,7 @@
@include('components.productpicker', array(
'products' => $products,
'barcodes' => $barcodes,
'nextInputSelector' => '#new_amount'
))

View File

@@ -0,0 +1,71 @@
@extends('layout.default')
@if($mode == 'edit')
@section('title', $__t('Edit Barcode'))
@else
@section('title', $__t('Create Barcode'))
@endif
@section('viewJsName', 'productbarcodesform')
@section('content')
<div class="row">
<div class="col">
<h2 class="title">@yield('title')</h2>
<hr>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-xs-12">
<h3 class="text-muted">{{ $__t('Barcode for product') }} <strong>{{ $product->name }}</strong></h3>
<script>Grocy.EditMode = '{{ $mode }}';</script>
@if($mode == 'edit')
<script>Grocy.EditObjectId = {{ $barcode->id }};</script>
@endif
<form id="barcode-form" novalidate>
<input type="hidden" name="product_id" value="{{ $product->id }}">
<div class="form-group">
<label for="name">{{ $__t('Barcode') }}<i class="fas fa-barcode"></i></label>
<div class="input-group">
<input type="text" class="form-control barcodescanner-input" required id="barcode" name="barcode" value="@if($mode == 'edit'){{ $barcode->barcode }}@endif" data-target="#scanned_barcode">
@include('components.barcodescanner')
</div>
</div>
@php if($mode == 'edit') { $value = $barcode->qu_factor_purchase_to_stock; } else { $value = 1; } @endphp
@include('components.numberpicker', array(
'id' => 'qu_factor_purchase_to_stock',
'label' => 'Factor purchase to stock quantity unit',
'min' => 1,
'value' => $value,
'isRequired' => true,
'invalidFeedback' => $__t('The amount cannot be lower than %s', '1'),
'additionalCssClasses' => 'input-group-qu',
))
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
<div class="form-group">
<label for="shopping_location_id_id">{{ $__t('Default store') }}</label>
<select class="form-control" id="shopping_location_id" name="shopping_location_id">
<option></option>
@foreach($shoppinglocations as $store)
<option @if($mode == 'edit' && $store->id == $product->shopping_location_id) selected="selected" @endif value="{{ $store->id }}">{{ $store->name }}</option>
@endforeach
</select>
</div>
@else
<input type="hidden" name="shopping_location_id" id="shopping_location_id" value="1">
@endif
<button id="save-barcode-button" class="btn btn-success">{{ $__t('Save') }}</button>
</form>
</div>
</div>
@stop

View File

@@ -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 = '';
@@ -56,7 +64,6 @@
@endphp
@include('components.productpicker', array(
'products' => $products,
'nextInputSelector' => '#barcode-taginput',
'prefillById' => $prefillById,
'disallowAllProductWorkflows' => true,
'isRequired' => false,
@@ -70,14 +77,6 @@
<textarea class="form-control wysiwyg-editor" id="description" name="description">@if($mode == 'edit'){{ $product->description }}@endif</textarea>
</div>
<div class="form-group tm-group">
<label for="barcode-taginput">{{ $__t('Barcode(s)') }}&nbsp;&nbsp;<i class="fas fa-barcode"></i></label>
<div class="input-group">
<input type="text" class="form-control tm-input barcodescanner-input" id="barcode-taginput" data-target="#barcode-taginput">
</div>
<div id="barcode-taginput-container"></div>
</div>
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
<div class="form-group">
<label for="location_id">{{ $__t('Default location') }}</label>
@@ -171,7 +170,8 @@
<div class="form-group">
<label for="qu_id_stock">{{ $__t('Quantity unit stock') }}</label>
<select required class="form-control input-group-qu" id="qu_id_stock" name="qu_id_stock">
<i class="fas fa-question-circle" data-toggle="tooltip" title="Quantity unit stock cannot be changed after first purchase"></i>
<select required class="form-control input-group-qu" id="qu_id_stock" name="qu_id_stock" @if($mode == 'edit') disabled @endif>
<option></option>
@foreach($quantityunits as $quantityunit)
<option @if($mode == 'edit' && $quantityunit->id == $product->qu_id_stock) selected="selected" @endif value="{{ $quantityunit->id }}" data-plural-form="{{ $quantityunit->name_plural }}">{{ $quantityunit->name }}</option>
@@ -295,7 +295,7 @@
<div class="col-lg-6 col-xs-12">
<h2>
{{ $__t('QU conversions') }}
<a id="qu-conversion-add-button" class="btn btn-outline-dark" href="#">
<a class="btn btn-outline-dark show-as-dialog-link" type="button" href="{{ $U('/quantityunitconversion/new?embedded&product=' . $product->id ) }}">
<i class="fas fa-plus"></i> {{ $__t('Add') }}
</a>
</h2>
@@ -316,7 +316,7 @@
@if($quConversion->product_id == $product->id || $quConversion->product_id == null)
<tr>
<td class="fit-content border-right">
<a class="btn btn-sm btn-info qu-conversion-edit-button @if($quConversion->product_id == null) disabled @endif" href="#" data-qu-conversion-id="{{ $quConversion->id }}">
<a class="btn btn-sm btn-info show-as-dialog-link @if($quConversion->product_id == null) disabled @endif" href="{{ $U('/quantityunitconversion/' . $quConversion->id . '?embedded&product=' . $product->id ) }}">
<i class="fas fa-edit"></i>
</a>
<a class="btn btn-sm btn-danger qu-conversion-delete-button @if($quConversion->product_id == null) disabled @endif" href="#" data-qu-conversion-id="{{ $quConversion->id }}">
@@ -346,6 +346,55 @@
</tbody>
</table>
<h2>
{{ $__t('Barcodes') }}
<a class="btn btn-outline-dark show-as-dialog-link" type="button" href="{{ $U('/productbarcodes/new?embedded&product=' . $product->id ) }}">
<i class="fas fa-plus"></i> {{ $__t('Add') }}
</a>
</h2>
<h5 id="barcode-headline-info" class="text-muted font-italic"></h5>
<table id="barcode-table" class="table table-sm table-striped dt-responsive">
<thead>
<tr>
<th class="border-right"></th>
<th>{{ $__t('Barcode') }}</th>
<th>{{ $__t('Factor purchase to stock quantity unit') }}</th>
<th>{{ $__t('Store') }}</th>
</tr>
</thead>
<tbody class="d-none">
@if($mode == "edit")
@foreach($barcodes as $barcode)
@if($barcode->product_id == $product->id || $barcode->product_id == null)
<tr>
<td class="fit-content border-right">
<a class="btn btn-sm btn-info show-as-dialog-link @if($barcode->product_id == null) disabled @endif" href="{{ $U('/productbarcodes/' . $barcode->id . '?embedded&product=' . $product->id ) }}">
<i class="fas fa-edit"></i>
</a>
<a class="btn btn-sm btn-danger barcode-delete-button @if($barcode->product_id == null) disabled @endif" href="#" data-barcode-id="{{ $barcode->id }}" data-barcode="{{ $barcode->barcode }}" data-product-barcode="{{ $product->barcode }}" data-product-id="{{ $product->id }}">
<i class="fas fa-trash"></i>
</a>
</td>
<td>
{{ $barcode->barcode }}
</td>
<td>
<span class="locale-number locale-number-quantity-amount">{{ $barcode->qu_factor_purchase_to_stock }}</span>
</td>
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
<td id="barcode-shopping-location">
@if (FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $barcode->shopping_location_id) !== null)
{{ FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $barcode->shopping_location_id)->name }}
@endif
</td>
@endif
</tr>
@endif
@endforeach
@endif
</tbody>
</table>
<div class="pt-5">
<label class="mt-2">{{ $__t('Picture') }}</label>
<button id="delete-current-product-picture-button" class="btn btn-sm btn-danger @if(empty($product->picture_file_name)) disabled @endif"><i class="fas fa-trash"></i> {{ $__t('Delete') }}</button>

View File

@@ -20,7 +20,7 @@
<hr>
<div class="row mt-3">
<div class="col-xs-12 col-md-2 col-xl-1">
<a class="btn btn-primary btn-sm responsive-button w-100 mb-3" href="{{ $U('/productgroup/new') }}">
<a class="btn btn-primary btn-sm responsive-button w-100 mb-3 show-as-dialog-link" href="{{ $U('/productgroup/new?embedded') }}">
{{ $__t('Add') }}
</a>
</div>
@@ -55,7 +55,7 @@
@foreach($productGroups as $productGroup)
<tr>
<td class="fit-content border-right">
<a class="btn btn-info btn-sm" href="{{ $U('/productgroup/') }}{{ $productGroup->id }}">
<a class="btn btn-info btn-sm show-as-dialog-link" href="{{ $U('/productgroup/') }}{{ $productGroup->id }}?embedded">
<i class="fas fa-edit"></i>
</a>
<a class="btn btn-danger btn-sm product-group-delete-button" href="#" data-group-id="{{ $productGroup->id }}" data-group-name="{{ $productGroup->name }}">

View File

@@ -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 }}

View File

@@ -30,6 +30,7 @@
@include('components.productpicker', array(
'products' => $products,
'barcodes' => $barcodes,
'nextInputSelector' => '#amount'
))
@@ -96,6 +97,16 @@
<input type="hidden" name="price" id="price" value="0">
@endif
@include('components.numberpicker', array(
'id' => 'qu_factor_purchase_to_stock',
'label' => 'Factor purchase to stock quantity unit',
'min' => 1,
'additionalGroupCssClasses' => 'd-none',
'invalidFeedback' => $__t('The amount cannot be lower than %s', '1'),
'additionalCssClasses' => 'input-group-qu',
'additionalHtmlElements' => '<p id="qu-conversion-info" class="form-text text-muted small d-none"></p>'
))
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
@include('components.locationpicker', array(
'locations' => $locations,

View File

@@ -134,7 +134,7 @@
<h5 class="card-title mb-1">{{ $recipe->name }}</h5>
<p class="card-text">
@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>
<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 (not included in costs), %s ingredient missing', 'Not enough in stock (not included in costs), %s ingredients missing') }}@endif</span>
</p>
</div>
</div>
@@ -250,7 +250,7 @@
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
<div class="col-5">
<label>{{ $__t('Costs') }}&nbsp;</label>
<i class="fas fa-question-circle" data-toggle="tooltip" title="{{ $__t('Based on the prices of the last purchase per product') }}"></i>
<i class="fas fa-question-circle" data-toggle="tooltip" title="{{ $__t('Based on the prices of the default consume rule which is "First expiring first, then first in first out"') }}"></i>
<h3 class="locale-number locale-number-currency pt-0">{{ $costs }}</h3>
</div>
@endif
@@ -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);
@@ -327,7 +330,7 @@
@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($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, %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>
<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>
@if(!empty($selectedRecipePosition->recipe_variable_amount))
<div class="small text-muted font-italic">{{ $__t('Variable amount') }}</div>

View File

@@ -41,6 +41,7 @@
<th>{{ $__t('Store') }}</th>
<th>{{ $__t('Price') }}</th>
@endif
<th>{{ $__t('Factor purchase to stock') }}</th>
<th>{{ $__t('Purchased date') }}</th>
@include('components.userfields_thead', array(
@@ -158,6 +159,9 @@
{{ $stockEntry->price }}
</td>
@endif
<td id="stock-{{ $stockEntry->id }}-qu-factor-purchase-to-stock">
{{ $stockEntry->qu_factor_purchase_to_stock }}
</td>
<td>
<span id="stock-{{ $stockEntry->id }}-purchased-date">{{ $stockEntry->purchased_date }}</span>
<time id="stock-{{ $stockEntry->id }}-purchased-date-timeago" class="timeago timeago-contextual" datetime="{{ $stockEntry->purchased_date }} 23:59:59"></time>

View File

@@ -60,6 +60,16 @@
'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>'
))
@include('components.numberpicker', array(
'id' => 'qu_factor_purchase_to_stock',
'label' => 'Factor purchase to stock quantity unit',
'value' => $stockEntry->qu_factor_purchase_to_stock,
'min' => 1,
'invalidFeedback' => $__t('The amount cannot be lower than %s', '1'),
'additionalCssClasses' => 'input-group-qu',
'additionalHtmlElements' => '<p id="qu-conversion-info" class="form-text text-muted small d-none"></p>'
))
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
@include('components.numberpicker', array(
'id' => 'price',

View File

@@ -104,11 +104,11 @@
<tr>
<th class="border-right"></th>
<th>{{ $__t('Product') }}</th>
<th>{{ $__t('Product group') }}</th>
<th>{{ $__t('Amount') }}</th>
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif">{{ $__t('Next best before date') }}</th>
<th class="d-none">Hidden location</th>
<th class="d-none">Hidden status</th>
<th class="d-none">Hidden product group</th>
@include('components.userfields_thead', array(
'userfields' => $userfields
@@ -206,9 +206,16 @@
<td class="product-name-cell cursor-link" data-product-id="{{ $currentStockEntry->product_id }}">
{{ FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name }}
</td>
@php $productGroup = FindObjectInArrayByPropertyValue($productGroups, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->product_group_id) @endphp
<td>
@if($productGroup !== null){{ $productGroup->name }}@endif
</td>
<td>
<span id="product-{{ $currentStockEntry->product_id }}-amount" class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span> <span id="product-{{ $currentStockEntry->product_id }}-qu-name">{{ $__n($currentStockEntry->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name_plural) }}</span>
<span id="product-{{ $currentStockEntry->product_id }}-opened-amount" class="small font-italic">@if($currentStockEntry->amount_opened > 0){{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif</span>
@if($currentStockEntry->amount != $currentStockEntry->factor_purchase_amount)
<span id="product-{{ $currentStockEntry->product_id }}-factor-purchase-amount" class="locale-number locale-number-quantity-amount">({{ $currentStockEntry->factor_purchase_amount }}</span> <span id="product-{{ $currentStockEntry->product_id }}-qu-purchase-name">{{ $__n($currentStockEntry->factor_purchase_amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_purchase)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_purchase)->name_plural) }})</span>
@endif
@if($currentStockEntry->is_aggregated_amount == 1)
<span class="pl-1 text-secondary">
<i class="fas fa-custom-sigma-sign"></i> <span id="product-{{ $currentStockEntry->product_id }}-amount-aggregated" class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount_aggregated }}</span> {{ $__n($currentStockEntry->amount_aggregated, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name_plural) }}
@@ -236,10 +243,6 @@
<td class="d-none">
@if($currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('-1 days')) && $currentStockEntry->amount > 0) expired @elseif($currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime("+$nextXDays days")) && $currentStockEntry->amount > 0) expiring @endif @if(FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) belowminstockamount @endif
</td>
@php $productGroup = FindObjectInArrayByPropertyValue($productGroups, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->product_group_id) @endphp
<td class="d-none">
@if($productGroup !== null){{ $productGroup->name }}@endif
</td>
@include('components.userfields_tbody', array(
'userfields' => $userfields,

View File

@@ -14,6 +14,7 @@
@include('components.productpicker', array(
'products' => $products,
'barcodes' => $barcodes,
'nextInputSelector' => '#location_id_from',
'disallowAddProductWorkflows' => true
))