diff --git a/controllers/StockController.php b/controllers/StockController.php index 7436d02d..e06a07ca 100644 --- a/controllers/StockController.php +++ b/controllers/StockController.php @@ -49,9 +49,7 @@ class StockController extends BaseController 'locations' => $this->Database->locations()->orderBy('name'), 'currentStockDetail' => $this->Database->stock()->orderBy('product_id'), 'currentStockLocations' => $this->StockService->GetCurrentStockLocations(), - 'missingProducts' => $this->StockService->GetMissingProducts(), 'nextXDays' => $nextXDays, - 'productGroups' => $this->Database->product_groups()->orderBy('name'), 'userfields' => $this->UserfieldsService->GetFields('products'), 'userfieldValues' => $this->UserfieldsService->GetAllValues('products') ]); diff --git a/localization/strings.pot b/localization/strings.pot index 408f8b77..2d9f91eb 100644 --- a/localization/strings.pot +++ b/localization/strings.pot @@ -1615,3 +1615,6 @@ msgstr "" msgid "Keep screen on while displaying a \"fullscreen-card\"" msgstr "" + +msgid "A purchased date is required" +msgstr "" diff --git a/public/js/grocy.js b/public/js/grocy.js index 7ee410ad..cb080592 100644 --- a/public/js/grocy.js +++ b/public/js/grocy.js @@ -614,10 +614,10 @@ $(document).on("click", ".show-as-dialog-link", function(e) backdrop: true, closeButton: false, buttons: { - ok: { - label: __t('OK'), - className: 'btn-success responsive-button', - callback: function() + cancel: { + label: __t('Cancel'), + className: 'btn-secondary responsive-button', + callback: function () { bootbox.hideAll(); } diff --git a/public/viewjs/consume.js b/public/viewjs/consume.js index 18d9f808..9faf4cca 100644 --- a/public/viewjs/consume.js +++ b/public/viewjs/consume.js @@ -1,24 +1,4 @@ -$(document).ready(function() { - - if (GetUriParam("embedded") !== undefined) - { - var locationId = GetUriParam('locationId'); - - if (typeof locationId === 'undefined') - { - Grocy.Components.ProductPicker.GetPicker().trigger('change'); - Grocy.Components.ProductPicker.GetInputElement().focus(); - } else { - - $("#location_id").val(locationId); - $("#location_id").trigger('change'); - $("#use_specific_stock_entry").click(); - $("#use_specific_stock_entry").trigger('change'); - } - } -}); - -$('#save-consume-button').on('click', function(e) +$('#save-consume-button').on('click', function(e) { e.preventDefault(); @@ -497,3 +477,21 @@ function UndoStockTransaction(transactionId) } ); }; + +if (GetUriParam("embedded") !== undefined) +{ + var locationId = GetUriParam('locationId'); + + if (typeof locationId === 'undefined') + { + Grocy.Components.ProductPicker.GetPicker().trigger('change'); + Grocy.Components.ProductPicker.GetInputElement().focus(); + } + else + { + $("#location_id").val(locationId); + $("#location_id").trigger('change'); + $("#use_specific_stock_entry").click(); + $("#use_specific_stock_entry").trigger('change'); + } +} diff --git a/public/viewjs/stockdetail.js b/public/viewjs/stockdetail.js index 2ee665c2..0772bd4a 100644 --- a/public/viewjs/stockdetail.js +++ b/public/viewjs/stockdetail.js @@ -7,45 +7,19 @@ }); $('#stock-detail-table tbody').removeClass("d-none"); -function bootBoxModal(message) { - bootbox.dialog({ - message: message, - size: 'large', - backdrop: true, - closeButton: false, - buttons: { - cancel: { - label: __t('Cancel'), - className: 'btn-secondary responsive-button', - callback: function() - { - bootbox.hideAll(); - } - } - } - }); -} +$.fn.dataTable.ext.search.push(function(settings, data, dataIndex) +{ + var productId = Grocy.Components.ProductPicker.GetValue(); + if ((isNaN(productId) || productId == "" || productId == data[1])) + { + return true; + } + + return false; +}); - -$.fn.dataTable.ext.search.push( - function( settings, data, dataIndex ) { - var productId = Grocy.Components.ProductPicker.GetValue(); - - if ( ( isNaN( productId ) || - productId == "" || - //assume productId is in the first column - productId == data[1] ) ) - { - return true; - } - return false; - } -); - -$(document).ready(function() { - Grocy.Components.ProductPicker.GetPicker().trigger('change'); -} ); +Grocy.Components.ProductPicker.GetPicker().trigger('change'); Grocy.Components.ProductPicker.GetPicker().on('change', function(e) { @@ -114,29 +88,17 @@ $(document).on('click', '.product-open-button', function(e) var productId = $(e.currentTarget).attr('data-product-id'); var productName = $(e.currentTarget).attr('data-product-name'); var productQuName = $(e.currentTarget).attr('data-product-qu-name'); + var specificStockEntryId = $(e.currentTarget).attr('data-stock-id'); + var stockRowId = $(e.currentTarget).attr('data-stockrow-id'); var button = $(e.currentTarget); - - Grocy.Api.Post('stock/products/' + productId + '/open', { 'amount': 1 }, + + Grocy.Api.Post('stock/products/' + productId + '/open', { 'amount': 1, 'stock_entry_id': specificStockEntryId }, function(bookingResponse) { - Grocy.Api.Get('stock/products/' + productId, - function(result) - { - if (result.stock_amount == result.stock_amount_opened) - { - button.addClass("disabled"); - } - - Grocy.FrontendHelpers.EndUiBusy(); - toastr.success(__t('Marked %1$s of %2$s as opened', 1 + " " + productQuName, productName) + '
' + __t("Undo") + ''); - RefreshProductRow(productId); - }, - function(xhr) - { - Grocy.FrontendHelpers.EndUiBusy(); - console.error(xhr); - } - ); + button.addClass("disabled"); + Grocy.FrontendHelpers.EndUiBusy(); + toastr.success(__t('Marked %1$s of %2$s as opened', 1 + " " + productQuName, productName) + '
' + __t("Undo") + ''); + RefreshStockDetailRow(stockRowId); }, function(xhr) { @@ -152,91 +114,40 @@ $(document).on("click", ".stock-name-cell", function(e) $("#stockdetail-productcard-modal").modal("show"); }); -$(document).on("click", ".product-purchase-button", function(e) -{ - e.preventDefault(); - - var productId = $(e.currentTarget).attr("data-product-id"); - - bootBoxModal(''); -}); - -$(document).on("click", ".product-transfer-button", function(e) -{ - - e.preventDefault(); - - var productId = $(e.currentTarget).attr("data-product-id"); - var locationId = $(e.currentTarget).attr('data-location-id'); - var specificStockEntryId = $(e.currentTarget).attr('data-stock-id'); - bootBoxModal(''); - -}); - -$(document).on("click", ".product-consume-custom-amount-button", function(e) -{ - e.preventDefault(); - - var productId = $(e.currentTarget).attr("data-product-id"); - var locationId = $(e.currentTarget).attr('data-location-id'); - var specificStockEntryId = $(e.currentTarget).attr('data-stock-id'); - - bootBoxModal(''); - -}); - -$(document).on("click", ".product-inventory-button", function(e) -{ - e.preventDefault(); - - var productId = $(e.currentTarget).attr("data-product-id"); - - bootBoxModal(''); -}); - -$(document).on("click", ".product-stockedit-button", function(e) -{ - e.preventDefault(); - - var productId = $(e.currentTarget).attr("data-product-id"); - var stockRowId = $(e.currentTarget).attr("data-id"); - - bootBoxModal(''); -}); - -$(document).on("click", ".product-add-to-shopping-list-button", function(e) -{ - e.preventDefault(); - - var productId = $(e.currentTarget).attr("data-product-id"); - - bootBoxModal(''); -}); - function RefreshStockDetailRow(stockRowId) { Grocy.Api.Get("stock/" + stockRowId + "/entry", function(result) { var stockRow = $('#stock-' + stockRowId + '-row'); - var now = moment(); - - stockRow.removeClass("table-warning"); - stockRow.removeClass("table-danger"); - stockRow.removeClass("table-info"); - stockRow.removeClass("d-none"); - stockRow.removeAttr("style"); - + if (result == null || result.amount == 0) { stockRow.fadeOut(500, function() { - //$(this).tooltip("hide"); $(this).addClass("d-none"); }); } else { + var expiringThreshold = moment().add(Grocy.UserSettings.stock_expring_soon_days, "days"); + var now = moment(); + var bestBeforeDate = moment(result.best_before_date); + + stockRow.removeClass("table-warning"); + stockRow.removeClass("table-danger"); + stockRow.removeClass("table-info"); + stockRow.removeClass("d-none"); + stockRow.removeAttr("style"); + if (now.isAfter(bestBeforeDate)) + { + stockRow.addClass("table-danger"); + } + else if (bestBeforeDate.isBefore(expiringThreshold)) + { + stockRow.addClass("table-warning"); + } + $('#stock-' + stockRowId + '-amount').parent().effect('highlight', { }, 500); $('#stock-' + stockRowId + '-amount').fadeOut(500, function () { @@ -248,6 +159,7 @@ function RefreshStockDetailRow(stockRowId) { $(this).text(result.best_before_date).fadeIn(500); }); + $('#stock-' + stockRowId + '-best-before-date-timeago').attr('datetime', result.best_before_date + ' 23:59:59'); var locationName = ""; Grocy.Api.Get("objects/locations/" + result.location_id, @@ -258,7 +170,8 @@ function RefreshStockDetailRow(stockRowId) function(xhr) { console.error(xhr); - }); + } + ); $('#stock-' + stockRowId + '-location').parent().effect('highlight', { }, 500); $('#stock-' + stockRowId + '-location').fadeOut(500, function() { @@ -276,8 +189,24 @@ function RefreshStockDetailRow(stockRowId) { $(this).text(result.purchased_date).fadeIn(500); }); + $('#stock-' + stockRowId + '-purchased-date-timeago').attr('datetime', result.purchased_date + ' 23:59:59'); + + $('#stock-' + stockRowId + '-opened-amount').parent().effect('highlight', {}, 500); + $('#stock-' + stockRowId + '-opened-amount').fadeOut(500, function () + { + if (result.open == 1) + { + $(this).text(__t('Opened')).fadeIn(500); + } + else + { + $(this).text("").fadeIn(500); + $(".product-open-button[data-stockrow-id='" + stockRowId + "']").removeClass("disabled"); + } + }); } + // Needs to be delayed because of the animation above the date-text would be wrong if fired immediately... setTimeout(function() { RefreshContextualTimeago(); @@ -316,3 +245,9 @@ function UndoStockBookingEntry(bookingId, stockRowId) } ); }; + +$(document).on("click", ".product-name-cell", function(e) +{ + Grocy.Components.ProductCard.Refresh($(e.currentTarget).attr("data-product-id")); + $("#productcard-modal").modal("show"); +}); diff --git a/public/viewjs/stockedit.js b/public/viewjs/stockedit.js index ca02abb2..109d092a 100644 --- a/public/viewjs/stockedit.js +++ b/public/viewjs/stockedit.js @@ -1,57 +1,4 @@ -$(document).ready(function() { - var stockRowId = GetUriParam('stockRowId'); - Grocy.Api.Get("stock/" + stockRowId + "/entry", - function(stockEntry) - { - Grocy.Components.LocationPicker.SetId(stockEntry.location_id); - $('#amount').val(stockEntry.amount); - $('#price').val(stockEntry.price); - Grocy.Components.DateTimePicker.SetValue(stockEntry.best_before_date); - - Grocy.Api.Get('stock/products/' + stockEntry.product_id, - function(productDetails) - { - $('#amount_qu_unit').text(productDetails.quantity_unit_stock.name); - - 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 cannot be lower than %1$s', 0.01.toLocaleString())); - } - else - { - $("#amount").attr("min", "1"); - $("#amount").attr("step", "1"); - $("#amount").parent().find(".invalid-feedback").text(__t('The amount cannot be lower than %1$s', '1')); - } - - if (productDetails.product.enable_tare_weight_handling == 1) - { - $("#amount").attr("min", productDetails.product.tare_weight); - $("#amount").parent().find(".invalid-feedback").text(__t('The amount cannot be lower than %1$s', parseFloat(productDetails.product.tare_weight).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: 2 }))); - $("#tare-weight-handling-info").removeClass("d-none"); - } - else - { - $("#tare-weight-handling-info").addClass("d-none"); - } - - }, - function(xhr) - { - console.error(xhr); - } - ); - }, - function(xhr) - { - console.error(xhr); - } - ); -} ); - -$('#save-stockedit-button').on('click', function(e) +$('#save-stockedit-button').on('click', function(e) { e.preventDefault(); @@ -76,8 +23,6 @@ $('#save-stockedit-button').on('click', function(e) } jsonData.price = price; - var bookingResponse = null; - var stockRowId = GetUriParam('stockRowId'); jsonData.id = stockRowId; @@ -135,3 +80,54 @@ if (Grocy.Components.DateTimePicker) Grocy.FrontendHelpers.ValidateForm('stockedit-form'); }); } + +var stockRowId = GetUriParam('stockRowId'); +Grocy.Api.Get("stock/" + stockRowId + "/entry", + function (stockEntry) + { + Grocy.Components.LocationPicker.SetId(stockEntry.location_id); + $('#amount').val(stockEntry.amount); + $('#price').val(stockEntry.price); + Grocy.Components.DateTimePicker.SetValue(stockEntry.best_before_date); + + Grocy.Api.Get('stock/products/' + stockEntry.product_id, + function (productDetails) + { + $('#amount_qu_unit').text(productDetails.quantity_unit_stock.name); + + 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 cannot be lower than %1$s', 0.01.toLocaleString())); + } + else + { + $("#amount").attr("min", "1"); + $("#amount").attr("step", "1"); + $("#amount").parent().find(".invalid-feedback").text(__t('The amount cannot be lower than %1$s', '1')); + } + + if (productDetails.product.enable_tare_weight_handling == 1) + { + $("#amount").attr("min", productDetails.product.tare_weight); + $("#amount").parent().find(".invalid-feedback").text(__t('The amount cannot be lower than %1$s', parseFloat(productDetails.product.tare_weight).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: 2 }))); + $("#tare-weight-handling-info").removeClass("d-none"); + } + else + { + $("#tare-weight-handling-info").addClass("d-none"); + } + + }, + function (xhr) + { + console.error(xhr); + } + ); + }, + function (xhr) + { + console.error(xhr); + } +); diff --git a/public/viewjs/stockoverview.js b/public/viewjs/stockoverview.js index 4047f197..c3d26bba 100644 --- a/public/viewjs/stockoverview.js +++ b/public/viewjs/stockoverview.js @@ -196,126 +196,6 @@ function RefreshStatistics() } RefreshStatistics(); -$(document).on("click", ".product-purchase-button", function(e) -{ - e.preventDefault(); - - var productId = $(e.currentTarget).attr("data-product-id"); - - bootbox.dialog({ - message: '', - size: 'large', - backdrop: true, - closeButton: false, - buttons: { - cancel: { - label: __t('Cancel'), - className: 'btn-secondary responsive-button', - callback: function() - { - bootbox.hideAll(); - } - } - } - }); -}); - -$(document).on("click", ".product-transfer-button", function(e) -{ - e.preventDefault(); - - var productId = $(e.currentTarget).attr("data-product-id"); - - bootbox.dialog({ - message: '', - size: 'large', - backdrop: true, - closeButton: false, - buttons: { - cancel: { - label: __t('Cancel'), - className: 'btn-secondary responsive-button', - callback: function() - { - bootbox.hideAll(); - } - } - } - }); -}); - -$(document).on("click", ".product-consume-custom-amount-button", function(e) -{ - e.preventDefault(); - - var productId = $(e.currentTarget).attr("data-product-id"); - - bootbox.dialog({ - message: '', - size: 'large', - backdrop: true, - closeButton: false, - buttons: { - cancel: { - label: __t('Cancel'), - className: 'btn-secondary responsive-button', - callback: function() - { - bootbox.hideAll(); - } - } - } - }); -}); - -$(document).on("click", ".product-inventory-button", function(e) -{ - e.preventDefault(); - - var productId = $(e.currentTarget).attr("data-product-id"); - - bootbox.dialog({ - message: '', - size: 'large', - backdrop: true, - closeButton: false, - buttons: { - cancel: { - label: __t('Cancel'), - className: 'btn-secondary responsive-button', - callback: function() - { - bootbox.hideAll(); - } - } - } - }); -}); - -$(document).on("click", ".product-add-to-shopping-list-button", function(e) -{ - e.preventDefault(); - - var productId = $(e.currentTarget).attr("data-product-id"); - - bootbox.dialog({ - message: '', - size: 'large', - backdrop: true, - closeButton: false, - buttons: { - cancel: { - label: __t('Cancel'), - className: 'btn-secondary responsive-button', - callback: function() - { - bootbox.hideAll(); - } - } - } - }); -}); - function RefreshProductRow(productId) { productId = productId.toString(); @@ -398,7 +278,7 @@ function RefreshProductRow(productId) { $(this).text(result.next_best_before_date).fadeIn(500); }); - $('#product-' + productId + '-next-best-before-date-timeago').attr('datetime', result.next_best_before_date); + $('#product-' + productId + '-next-best-before-date-timeago').attr('datetime', result.next_best_before_date + ' 23:59:59'); if (result.stock_amount_opened > 0) { diff --git a/public/viewjs/transfer.js b/public/viewjs/transfer.js index 88d2d111..1918befa 100644 --- a/public/viewjs/transfer.js +++ b/public/viewjs/transfer.js @@ -1,23 +1,4 @@ -$(document).ready(function() { - if (GetUriParam("embedded") !== undefined) - { - var locationId = GetUriParam('locationId'); - - if (typeof locationId === 'undefined') - { - Grocy.Components.ProductPicker.GetPicker().trigger('change'); - Grocy.Components.ProductPicker.GetInputElement().focus(); - } else { - - $("#location_id_from").val(locationId); - $("#location_id_from").trigger('change'); - $("#use_specific_stock_entry").click(); - $("#use_specific_stock_entry").trigger('change'); - } - } -}); - -$('#save-transfer-button').on('click', function(e) +$('#save-transfer-button').on('click', function(e) { e.preventDefault(); @@ -440,3 +421,22 @@ function UndoStockTransaction(transactionId) } ); }; + +if (GetUriParam("embedded") !== undefined) +{ + var locationId = GetUriParam('locationId'); + + if (typeof locationId === 'undefined') + { + Grocy.Components.ProductPicker.GetPicker().trigger('change'); + Grocy.Components.ProductPicker.GetInputElement().focus(); + } + else + { + + $("#location_id_from").val(locationId); + $("#location_id_from").trigger('change'); + $("#use_specific_stock_entry").click(); + $("#use_specific_stock_entry").trigger('change'); + } +} diff --git a/views/stockdetail.blade.php b/views/stockdetail.blade.php index 53b6a146..1b11535b 100644 --- a/views/stockdetail.blade.php +++ b/views/stockdetail.blade.php @@ -9,21 +9,16 @@ @endpush -@push('pageStyles') - -@endpush - @section('content')

@yield('title')

- @include('components.productpicker', array('products' => $products,'disallowAddProductWorkflows' => true)) + @include('components.productpicker', array( + 'products' => $products, + 'disallowAllProductWorkflows' => true + ))
@@ -48,19 +43,9 @@ @foreach($currentStockDetail as $currentStockEntry) - amount > 0) table-warning @elseif (FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) table-info @endif"> + amount > 0) table-warning @endif"> - - 1 - - - {{ $__t('All') }} + @if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING) - - 1 + data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name }}" + data-stock-id="{{ $currentStockEntry->stock_id }}" + data-stockrow-id="{{ $currentStockEntry->id }}"> + + + + @endif -