2018-07-08 15:16:24 +02:00
var stockOverviewTable = $ ( '#stock-overview-table' ) . DataTable ( {
2020-08-17 14:47:33 -05:00
'order' : [ [ 4 , 'asc' ] ] ,
2018-05-12 16:15:28 +02:00
'columnDefs' : [
2019-01-05 16:27:26 +01:00
{ 'orderable' : false , 'targets' : 0 } ,
2020-01-03 14:18:56 +01:00
{ 'searchable' : false , "targets" : 0 } ,
2020-08-17 14:47:33 -05:00
{ 'searchable' : false , "targets" : 0 } ,
2020-08-24 17:57:43 +02:00
{ 'visible' : false , 'targets' : 6 } ,
2020-10-15 12:46:27 -05:00
{ 'visible' : false , 'targets' : 7 } ,
2020-11-11 21:11:17 +01:00
{ 'visible' : false , 'targets' : 8 } ,
{ 'visible' : false , 'targets' : 2 } ,
2020-11-11 22:06:01 +01:00
{ 'visible' : false , 'targets' : 4 } ,
2020-11-11 22:38:01 +01:00
{ 'visible' : false , 'targets' : 9 } ,
2020-12-17 17:33:24 +01:00
{ 'visible' : false , 'targets' : 10 } ,
2020-12-19 10:51:07 +01:00
{ 'visible' : false , 'targets' : 11 } ,
{ 'visible' : false , 'targets' : 12 } ,
2020-12-19 17:25:13 +01:00
{ 'visible' : false , 'targets' : 13 } ,
2020-12-17 17:33:24 +01:00
{ "type" : "num" , "targets" : 3 } ,
{ "type" : "html-num-fmt" , "targets" : 9 } ,
{ "type" : "html-num-fmt" , "targets" : 10 } ,
2020-12-19 10:51:07 +01:00
{ "type" : "html" , "targets" : 5 } ,
{ "type" : "html" , "targets" : 11 } ,
{ "type" : "html-num-fmt" , "targets" : 12 } ,
2020-12-19 17:25:13 +01:00
{ "type" : "num" , "targets" : 13 }
2020-12-07 19:48:33 +01:00
] . concat ( $ . fn . dataTable . defaults . columnDefs )
2018-07-08 15:16:24 +02:00
} ) ;
2020-11-07 14:53:45 +01:00
2019-01-05 14:27:40 +01:00
$ ( '#stock-overview-table tbody' ) . removeClass ( "d-none" ) ;
2019-03-04 17:43:12 +01:00
stockOverviewTable . columns . adjust ( ) . draw ( ) ;
2018-07-08 15:16:24 +02:00
2018-07-08 16:54:37 +02:00
$ ( "#location-filter" ) . on ( "change" , function ( )
2018-07-08 15:16:24 +02:00
{
2018-07-08 16:54:37 +02:00
var value = $ ( this ) . val ( ) ;
if ( value === "all" )
2018-07-08 15:16:24 +02:00
{
2018-07-08 16:54:37 +02:00
value = "" ;
}
2020-08-25 20:20:51 +02:00
else
{
value = "xx" + value + "xx" ;
}
2019-01-19 00:37:21 -07:00
2020-10-15 12:46:27 -05:00
stockOverviewTable . column ( 6 ) . search ( value ) . draw ( ) ;
2018-07-08 16:54:37 +02:00
} ) ;
2018-07-08 15:16:24 +02:00
2018-10-06 18:19:31 +02:00
$ ( "#product-group-filter" ) . on ( "change" , function ( )
{
var value = $ ( this ) . val ( ) ;
if ( value === "all" )
{
value = "" ;
}
2020-08-25 20:20:51 +02:00
else
{
value = "xx" + value + "xx" ;
}
2020-08-29 16:41:27 +02:00
2020-10-15 12:46:27 -05:00
stockOverviewTable . column ( 8 ) . search ( value ) . draw ( ) ;
2018-10-06 18:19:31 +02:00
} ) ;
2018-09-24 19:13:53 +02:00
$ ( "#status-filter" ) . on ( "change" , function ( )
{
var value = $ ( this ) . val ( ) ;
if ( value === "all" )
{
value = "" ;
}
// Transfer CSS classes of selected element to dropdown element (for background)
$ ( this ) . attr ( "class" , $ ( "#" + $ ( this ) . attr ( "id" ) + " option[value='" + value + "']" ) . attr ( "class" ) + " form-control" ) ;
2019-01-19 00:37:21 -07:00
2020-10-15 12:46:27 -05:00
stockOverviewTable . column ( 7 ) . search ( value ) . draw ( ) ;
2018-09-24 19:13:53 +02:00
} ) ;
2020-04-19 08:51:02 -04:00
$ ( ".status-filter-message" ) . on ( "click" , function ( )
2018-09-24 19:13:53 +02:00
{
var value = $ ( this ) . data ( "status-filter" ) ;
$ ( "#status-filter" ) . val ( value ) ;
$ ( "#status-filter" ) . trigger ( "change" ) ;
} ) ;
2020-08-25 20:20:51 +02:00
$ ( "#clear-filter-button" ) . on ( "click" , function ( )
{
$ ( "#search" ) . val ( "" ) ;
$ ( "#status-filter" ) . val ( "all" ) ;
$ ( "#product-group-filter" ) . val ( "all" ) ;
$ ( "#location-filter" ) . val ( "all" ) ;
stockOverviewTable . column ( 6 ) . search ( "" ) . draw ( ) ;
stockOverviewTable . column ( 7 ) . search ( "" ) . draw ( ) ;
2020-10-15 12:46:27 -05:00
stockOverviewTable . column ( 8 ) . search ( "" ) . draw ( ) ;
2020-08-25 20:20:51 +02:00
stockOverviewTable . search ( "" ) . draw ( ) ;
} ) ;
2019-10-15 19:59:14 +02:00
$ ( "#search" ) . on ( "keyup" , Delay ( function ( )
2018-07-08 16:54:37 +02:00
{
var value = $ ( this ) . val ( ) ;
if ( value === "all" )
{
value = "" ;
}
2019-01-19 00:37:21 -07:00
2018-07-08 16:54:37 +02:00
stockOverviewTable . search ( value ) . draw ( ) ;
2019-10-15 19:59:14 +02:00
} , 200 ) ) ;
2018-05-12 16:15:28 +02:00
$ ( document ) . on ( 'click' , '.product-consume-button' , function ( e )
{
2018-09-24 09:30:26 +02:00
e . preventDefault ( ) ;
2018-09-25 16:24:43 +02:00
// Remove the focus from the current button
// to prevent that the tooltip stays until clicked anywhere else
document . activeElement . blur ( ) ;
2018-11-24 19:40:50 +01:00
Grocy . FrontendHelpers . BeginUiBusy ( ) ;
2019-01-19 00:37:21 -07:00
2018-05-12 16:15:28 +02:00
var productId = $ ( e . currentTarget ) . attr ( 'data-product-id' ) ;
2018-05-13 08:42:45 +02:00
var consumeAmount = $ ( e . currentTarget ) . attr ( 'data-consume-amount' ) ;
2020-04-13 17:29:00 +02:00
var originalTotalStockAmount = $ ( e . currentTarget ) . attr ( 'data-original-total-stock-amount' ) ;
2019-07-06 18:15:53 +02:00
var wasSpoiled = $ ( e . currentTarget ) . hasClass ( "product-consume-button-spoiled" ) ;
2018-05-12 16:15:28 +02:00
2020-12-07 19:48:33 +01:00
Grocy . Api . Post ( 'stock/products/' + productId + '/consume' , { 'amount' : consumeAmount , 'spoiled' : wasSpoiled , 'allow_subproduct_substitution' : true } ,
2019-09-20 13:37:53 +02:00
function ( bookingResponse )
2018-05-12 16:15:28 +02:00
{
2019-01-19 14:51:51 +01:00
Grocy . Api . Get ( 'stock/products/' + productId ,
2018-08-07 20:11:08 +02:00
function ( result )
2018-05-13 08:42:45 +02:00
{
2020-04-13 17:29:00 +02:00
if ( result . product . enable _tare _weight _handling == 1 )
{
2020-12-20 14:43:07 +01:00
var toastMessage = _ _t ( 'Removed %1$s of %2$s from stock' , parseFloat ( originalTotalStockAmount ) . toLocaleString ( { minimumFractionDigits : 0 , maximumFractionDigits : Grocy . UserSettings . stock _decimal _places _amounts } ) + " " + _ _n ( consumeAmount , result . quantity _unit _stock . name , result . quantity _unit _stock . name _plural ) , result . product . name ) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse [ 0 ] . transaction _id + '\')"><i class="fas fa-undo"></i> ' + _ _t ( "Undo" ) + '</a>' ;
2020-04-13 17:29:00 +02:00
}
else
{
2020-12-20 14:43:07 +01:00
var toastMessage = _ _t ( 'Removed %1$s of %2$s from stock' , parseFloat ( consumeAmount ) . toLocaleString ( { minimumFractionDigits : 0 , maximumFractionDigits : Grocy . UserSettings . stock _decimal _places _amounts } ) + " " + _ _n ( consumeAmount , result . quantity _unit _stock . name , result . quantity _unit _stock . name _plural ) , result . product . name ) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse [ 0 ] . transaction _id + '\')"><i class="fas fa-undo"></i> ' + _ _t ( "Undo" ) + '</a>' ;
2020-04-13 17:29:00 +02:00
}
2020-08-29 16:41:27 +02:00
2019-07-06 18:15:53 +02:00
if ( wasSpoiled )
{
toastMessage += " (" + _ _t ( "Spoiled" ) + ")" ;
}
2018-11-24 19:40:50 +01:00
Grocy . FrontendHelpers . EndUiBusy ( ) ;
2019-07-06 18:15:53 +02:00
toastr . success ( toastMessage ) ;
2018-08-07 20:11:08 +02:00
RefreshStatistics ( ) ;
2019-09-20 13:37:53 +02:00
RefreshProductRow ( productId ) ;
2018-08-07 20:11:08 +02:00
} ,
function ( xhr )
{
2018-11-24 19:40:50 +01:00
Grocy . FrontendHelpers . EndUiBusy ( ) ;
2018-08-07 20:11:08 +02:00
console . error ( xhr ) ;
}
) ;
2018-05-12 16:15:28 +02:00
} ,
function ( xhr )
{
2018-11-24 19:40:50 +01:00
Grocy . FrontendHelpers . EndUiBusy ( ) ;
2018-05-12 16:15:28 +02:00
console . error ( xhr ) ;
}
) ;
} ) ;
2018-08-04 14:25:32 +02:00
2018-11-17 19:39:37 +01:00
$ ( document ) . on ( 'click' , '.product-open-button' , function ( e )
{
e . preventDefault ( ) ;
// Remove the focus from the current button
// to prevent that the tooltip stays until clicked anywhere else
document . activeElement . blur ( ) ;
2018-11-24 19:40:50 +01:00
Grocy . FrontendHelpers . BeginUiBusy ( ) ;
2019-01-19 00:37:21 -07:00
2018-11-17 19:39:37 +01:00
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' ) ;
2020-11-15 09:57:45 +01:00
var amount = $ ( e . currentTarget ) . attr ( 'data-open-amount' ) ;
2018-11-18 13:35:21 +01:00
var button = $ ( e . currentTarget ) ;
2018-11-17 19:39:37 +01:00
2020-12-07 19:48:33 +01:00
Grocy . Api . Post ( 'stock/products/' + productId + '/open' , { 'amount' : amount , 'allow_subproduct_substitution' : true } ,
2019-09-20 13:37:53 +02:00
function ( bookingResponse )
2018-11-17 19:39:37 +01:00
{
2019-01-19 14:51:51 +01:00
Grocy . Api . Get ( 'stock/products/' + productId ,
2018-11-17 19:39:37 +01:00
function ( result )
{
2018-11-18 13:35:21 +01:00
if ( result . stock _amount == result . stock _amount _opened )
{
button . addClass ( "disabled" ) ;
}
2018-11-24 19:40:50 +01:00
Grocy . FrontendHelpers . EndUiBusy ( ) ;
2020-12-20 14:43:07 +01:00
toastr . success ( _ _t ( 'Marked %1$s of %2$s as opened' , parseFloat ( amount ) . toLocaleString ( { minimumFractionDigits : 0 , maximumFractionDigits : Grocy . UserSettings . stock _decimal _places _amounts } ) + " " + productQuName , productName ) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse [ 0 ] . transaction _id + '\')"><i class="fas fa-undo"></i> ' + _ _t ( "Undo" ) + '</a>' ) ;
2018-11-17 19:39:37 +01:00
RefreshStatistics ( ) ;
2019-09-20 13:37:53 +02:00
RefreshProductRow ( productId ) ;
2018-11-17 19:39:37 +01:00
} ,
function ( xhr )
{
2018-11-24 19:40:50 +01:00
Grocy . FrontendHelpers . EndUiBusy ( ) ;
2018-11-17 19:39:37 +01:00
console . error ( xhr ) ;
}
) ;
} ,
function ( xhr )
{
2018-11-24 19:40:50 +01:00
Grocy . FrontendHelpers . EndUiBusy ( ) ;
2018-11-17 19:39:37 +01:00
console . error ( xhr ) ;
}
) ;
} ) ;
2018-10-01 20:20:50 +02:00
$ ( document ) . on ( "click" , ".product-name-cell" , function ( e )
2018-09-30 23:22:17 +02:00
{
2018-10-22 19:28:59 +02:00
Grocy . Components . ProductCard . Refresh ( $ ( e . currentTarget ) . attr ( "data-product-id" ) ) ;
$ ( "#stockoverview-productcard-modal" ) . modal ( "show" ) ;
2018-09-30 23:22:17 +02:00
} ) ;
2018-08-04 14:25:32 +02:00
function RefreshStatistics ( )
{
2019-01-19 00:37:21 -07:00
Grocy . Api . Get ( 'stock' ,
2018-08-04 14:25:32 +02:00
function ( result )
{
var amountSum = 0 ;
2020-08-30 12:18:16 +02:00
result . forEach ( element =>
{
2018-08-04 14:25:32 +02:00
amountSum += parseInt ( element . amount ) ;
} ) ;
2020-10-15 12:46:27 -05:00
if ( ! Grocy . FeatureFlags . GROCY _FEATURE _FLAG _STOCK _PRICE _TRACKING )
{
$ ( "#info-current-stock" ) . text ( _ _n ( result . length , '%s Product' , '%s Products' ) ) ;
}
else
{
var valueSum = 0 ;
result . forEach ( element =>
{
valueSum += parseInt ( element . value ) ;
} ) ;
$ ( "#info-current-stock" ) . text ( _ _n ( result . length , '%s Product' , '%s Products' ) + ", " + _ _t ( '%s total value' , valueSum . toLocaleString ( undefined , { style : "currency" , currency : Grocy . Currency } ) ) ) ;
}
2018-08-04 14:25:32 +02:00
} ,
function ( xhr )
{
console . error ( xhr ) ;
}
) ;
2020-11-15 19:53:44 +01:00
var nextXDays = $ ( "#info-duesoon-products" ) . data ( "next-x-days" ) ;
Grocy . Api . Get ( 'stock/volatile?due_soon_days=' + nextXDays ,
2018-08-04 14:25:32 +02:00
function ( result )
{
2020-11-15 19:53:44 +01:00
$ ( "#info-duesoon-products" ) . html ( '<span class="d-block d-md-none">' + result . due _products . length + ' <i class="fas fa-clock"></i></span><span class="d-none d-md-block">' + _ _n ( result . due _products . length , '%s product is due' , '%s products are due' ) + ' ' + _ _n ( nextXDays , 'within the next day' , 'within the next %s days' ) + '</span>' ) ;
$ ( "#info-overdue-products" ) . html ( '<span class="d-block d-md-none">' + result . overdue _products . length + ' <i class="fas fa-times-circle"></i></span><span class="d-none d-md-block">' + _ _n ( result . overdue _products . length , '%s product is overdue' , '%s products are overdue' ) + '</span>' ) ;
$ ( "#info-expired-products" ) . html ( '<span class="d-block d-md-none">' + result . expired _products . length + ' <i class="fas fa-times-circle"></i></span><span class="d-none d-md-block">' + _ _n ( result . expired _products . length , '%s product is expired' , '%s products are expired' ) + '</span>' ) ;
2020-11-07 14:53:45 +01:00
$ ( "#info-missing-products" ) . html ( '<span class="d-block d-md-none">' + result . missing _products . length + ' <i class="fas fa-exclamation-circle"></i></span><span class="d-none d-md-block">' + _ _n ( result . missing _products . length , '%s product is below defined min. stock amount' , '%s products are below defined min. stock amount' ) + '</span>' ) ;
2018-08-04 14:25:32 +02:00
} ,
function ( xhr )
{
console . error ( xhr ) ;
}
) ;
}
RefreshStatistics ( ) ;
2019-09-20 13:37:53 +02:00
function RefreshProductRow ( productId )
{
productId = productId . toString ( ) ;
Grocy . Api . Get ( 'stock/products/' + productId ,
function ( result )
{
2019-09-27 08:30:08 +02:00
// Also refresh the parent product, if any
if ( result . product . parent _product _id !== null && ! result . product . parent _product _id . toString ( ) . isEmpty ( ) )
{
RefreshProductRow ( result . product . parent _product _id ) ;
}
2019-09-20 13:37:53 +02:00
var productRow = $ ( '#product-' + productId + '-row' ) ;
2020-11-15 19:53:44 +01:00
var dueSoonThreshold = moment ( ) . add ( $ ( "#info-duesoon-products" ) . data ( "next-x-days" ) , "days" ) ;
2019-09-20 13:37:53 +02:00
var now = moment ( ) ;
2020-11-15 19:53:44 +01:00
var nextDueDate = moment ( result . next _due _date ) ;
2020-08-29 16:41:27 +02:00
2019-09-20 13:37:53 +02:00
productRow . removeClass ( "table-warning" ) ;
productRow . removeClass ( "table-danger" ) ;
2020-11-15 19:53:44 +01:00
productRow . removeClass ( "table-secondary" ) ;
2019-09-26 13:55:42 +02:00
productRow . removeClass ( "table-info" ) ;
productRow . removeClass ( "d-none" ) ;
productRow . removeAttr ( "style" ) ;
2020-11-15 19:53:44 +01:00
if ( now . isAfter ( nextDueDate ) )
2019-09-20 13:37:53 +02:00
{
2020-11-15 19:53:44 +01:00
if ( result . product . due _type == 1 )
{
productRow . addClass ( "table-secondary" ) ;
}
else
{
productRow . addClass ( "table-danger" ) ;
}
2019-09-20 13:37:53 +02:00
}
2020-11-15 19:53:44 +01:00
else if ( nextDueDate . isBefore ( dueSoonThreshold ) )
2019-09-20 13:37:53 +02:00
{
productRow . addClass ( "table-warning" ) ;
}
2020-08-25 18:15:34 +02:00
if ( result . stock _amount == 0 && result . stock _amount _aggregated == 0 && result . product . min _stock _amount == 0 )
2019-09-20 13:37:53 +02:00
{
2020-01-28 19:27:18 +01:00
animateCSS ( "#product-" + productId + "-row" , "fadeOut" , function ( )
2019-09-20 13:37:53 +02:00
{
2020-01-28 19:27:18 +01:00
$ ( "#product-" + productId + "-row" ) . tooltip ( "hide" ) ;
$ ( "#product-" + productId + "-row" ) . addClass ( "d-none" ) ;
2019-09-20 13:37:53 +02:00
} ) ;
}
else
{
2020-01-28 19:27:18 +01:00
animateCSS ( "#product-" + productId + "-row td:not(:first)" , "shake" ) ;
2019-09-20 13:37:53 +02:00
$ ( '#product-' + productId + '-qu-name' ) . text ( _ _n ( result . stock _amount , result . quantity _unit _stock . name , result . quantity _unit _stock . name _plural ) ) ;
2020-01-28 19:27:18 +01:00
$ ( '#product-' + productId + '-amount' ) . text ( result . stock _amount ) ;
2019-09-20 13:37:53 +02:00
$ ( '#product-' + productId + '-consume-all-button' ) . attr ( 'data-consume-amount' , result . stock _amount ) ;
2020-10-15 12:46:27 -05:00
$ ( '#product-' + productId + '-value' ) . text ( result . stock _value ) ;
2020-11-15 19:53:44 +01:00
$ ( '#product-' + productId + '-next-due-date' ) . text ( result . next _due _date ) ;
$ ( '#product-' + productId + '-next-due-date-timeago' ) . attr ( 'datetime' , result . next _due _date ) ;
2019-09-20 13:37:53 +02:00
var openedAmount = result . stock _amount _opened || 0 ;
2020-01-28 19:27:18 +01:00
if ( openedAmount > 0 )
2019-09-20 13:37:53 +02:00
{
2020-01-28 19:27:18 +01:00
$ ( '#product-' + productId + '-opened-amount' ) . text ( _ _t ( '%s opened' , openedAmount ) ) ;
}
else
{
$ ( '#product-' + productId + '-opened-amount' ) . text ( "" ) ;
}
2019-09-26 13:55:42 +02:00
if ( result . stock _amount == 0 && result . product . min _stock _amount > 0 )
{
productRow . addClass ( "table-info" ) ;
}
2019-09-20 13:37:53 +02:00
}
2020-11-15 19:53:44 +01:00
$ ( '#product-' + productId + '-next-due-date' ) . text ( result . next _due _date ) ;
$ ( '#product-' + productId + '-next-due-date-timeago' ) . attr ( 'datetime' , result . next _due _date + ' 23:59:59' ) ;
2019-09-20 13:37:53 +02:00
if ( result . stock _amount _opened > 0 )
{
2020-01-28 19:27:18 +01:00
$ ( '#product-' + productId + '-opened-amount' ) . text ( _ _t ( '%s opened' , result . stock _amount _opened ) ) ;
2019-09-20 13:37:53 +02:00
}
else
{
$ ( '#product-' + productId + '-opened-amount' ) . text ( "" ) ;
}
2019-09-27 08:30:08 +02:00
if ( parseInt ( result . is _aggregated _amount ) === 1 )
{
2020-01-28 19:27:18 +01:00
$ ( '#product-' + productId + '-amount-aggregated' ) . text ( result . stock _amount _aggregated ) ;
2019-09-27 08:30:08 +02:00
if ( result . stock _amount _opened _aggregated > 0 )
{
2020-01-28 19:27:18 +01:00
$ ( '#product-' + productId + '-opened-amount-aggregated' ) . text ( _ _t ( '%s opened' , result . stock _amount _opened _aggregated ) ) ;
2019-09-27 08:30:08 +02:00
}
else
{
$ ( '#product-' + productId + '-opened-amount-aggregated' ) . text ( "" ) ;
}
}
2019-09-20 13:37:53 +02:00
// Needs to be delayed because of the animation above the date-text would be wrong if fired immediately...
setTimeout ( function ( )
{
2020-01-27 19:00:49 +01:00
RefreshContextualTimeago ( "#product-" + productId + "-row" ) ;
RefreshLocaleNumberDisplay ( "#product-" + productId + "-row" ) ;
2019-09-20 13:37:53 +02:00
} , 600 ) ;
} ,
function ( xhr )
{
Grocy . FrontendHelpers . EndUiBusy ( ) ;
console . error ( xhr ) ;
}
) ;
}
$ ( window ) . on ( "message" , function ( e )
{
var data = e . originalEvent . data ;
if ( data . Message === "ProductChanged" )
{
RefreshProductRow ( data . Payload ) ;
RefreshStatistics ( ) ;
}
} ) ;