2020-01-27 19:19:09 +01:00
var stockEntriesTable = $ ( '#stockentries-table' ) . DataTable ( {
2019-12-19 12:48:36 -06:00
'order' : [ [ 2 , 'asc' ] ] ,
'columnDefs' : [
{ 'orderable' : false , 'targets' : 0 } ,
2021-07-12 18:25:07 +02:00
{ 'searchable' : false , "targets" : 0 } ,
2021-11-25 19:08:53 +01:00
{ 'visible' : false , 'targets' : 10 } ,
2022-02-06 21:09:34 +01:00
{ "type" : "num" , "targets" : 1 } ,
2022-11-12 18:10:32 +01:00
{ "type" : "custom-sort" , "targets" : 3 } ,
2021-11-25 19:08:53 +01:00
{ "type" : "html" , "targets" : 4 } ,
2022-11-12 18:10:32 +01:00
{ "type" : "custom-sort" , "targets" : 7 } ,
2022-02-06 21:09:34 +01:00
{ "type" : "html" , "targets" : 8 } ,
{ "type" : "html" , "targets" : 9 }
2020-12-07 19:48:33 +01:00
] . concat ( $ . fn . dataTable . defaults . columnDefs )
2019-12-19 12:48:36 -06:00
} ) ;
2020-01-27 19:19:09 +01:00
$ ( '#stockentries-table tbody' ) . removeClass ( "d-none" ) ;
2020-11-15 14:30:00 +01:00
stockEntriesTable . columns . adjust ( ) . draw ( ) ;
2019-12-19 12:48:36 -06:00
2020-01-21 17:30:09 +01:00
$ . fn . dataTable . ext . search . push ( function ( settings , data , dataIndex )
{
var productId = Grocy . Components . ProductPicker . GetValue ( ) ;
2019-12-19 12:48:36 -06:00
2025-02-27 17:07:30 +01:00
if ( ! productId || Number . isNaN ( productId ) || productId == data [ stockEntriesTable . colReorder . transpose ( 1 ) ] )
2020-01-21 17:30:09 +01:00
{
return true ;
}
2020-08-29 16:41:27 +02:00
2020-01-21 17:30:09 +01:00
return false ;
} ) ;
2019-12-19 12:48:36 -06:00
2020-11-15 14:48:48 +01:00
$ ( "#clear-filter-button" ) . on ( "click" , function ( )
{
2022-04-03 19:28:59 +02:00
$ ( "#location-filter" ) . val ( "all" ) ;
$ ( "#location-filter" ) . trigger ( "change" ) ;
2025-01-11 12:06:15 +01:00
if ( GetUriParam ( "embedded" ) === undefined )
{
Grocy . Components . ProductPicker . Clear ( ) ;
}
2020-11-15 14:48:48 +01:00
stockEntriesTable . draw ( ) ;
} ) ;
2019-12-19 12:48:36 -06:00
2022-04-03 19:28:59 +02:00
$ ( "#location-filter" ) . on ( "change" , function ( )
{
var value = $ ( this ) . val ( ) ;
var text = $ ( "#location-filter option:selected" ) . text ( ) ;
if ( value === "all" )
{
text = "" ;
}
stockEntriesTable . column ( stockEntriesTable . colReorder . transpose ( 5 ) ) . search ( text ) . draw ( ) ;
} ) ;
2019-12-19 12:48:36 -06:00
Grocy . Components . ProductPicker . GetPicker ( ) . on ( 'change' , function ( e )
{
2020-01-27 19:19:09 +01:00
stockEntriesTable . draw ( ) ;
2019-12-19 12:48:36 -06:00
} ) ;
2020-11-15 14:48:48 +01:00
Grocy . Components . ProductPicker . GetInputElement ( ) . on ( 'keyup' , function ( e )
{
stockEntriesTable . draw ( ) ;
} ) ;
2019-12-19 12:48:36 -06:00
$ ( document ) . on ( 'click' , '.stock-consume-button' , function ( e )
{
e . preventDefault ( ) ;
Grocy . FrontendHelpers . BeginUiBusy ( ) ;
var productId = $ ( e . currentTarget ) . attr ( 'data-product-id' ) ;
var locationId = $ ( e . currentTarget ) . attr ( 'data-location-id' ) ;
var specificStockEntryId = $ ( e . currentTarget ) . attr ( 'data-stock-id' ) ;
var stockRowId = $ ( e . currentTarget ) . attr ( 'data-stockrow-id' ) ;
2023-02-06 20:22:10 +01:00
var consumeAmount = Number . parseFloat ( $ ( e . currentTarget ) . attr ( 'data-consume-amount' ) ) ;
2019-12-19 12:48:36 -06:00
2020-01-17 10:54:34 -06:00
var wasSpoiled = $ ( e . currentTarget ) . hasClass ( "stock-consume-button-spoiled" ) ;
2019-12-19 12:48:36 -06:00
2020-10-18 14:51:32 +02:00
Grocy . Api . Post ( 'stock/products/' + productId + '/consume' , { 'amount' : consumeAmount , 'spoiled' : wasSpoiled , 'location_id' : locationId , 'stock_entry_id' : specificStockEntryId , 'exact_amount' : true } ,
2019-12-19 12:48:36 -06:00
function ( bookingResponse )
{
Grocy . Api . Get ( 'stock/products/' + productId ,
function ( result )
{
2024-02-09 16:29:19 +01:00
var toastMessage = _ _t ( 'Removed %1$s of %2$s from stock' , consumeAmount . toLocaleString ( { minimumFractionDigits : 0 , maximumFractionDigits : Grocy . UserSettings . stock _decimal _places _amounts } ) + " " + _ _n ( consumeAmount , result . quantity _unit _stock . name , result . quantity _unit _stock . name _plural , true ) , result . product . name ) ;
2019-12-19 12:48:36 -06:00
if ( wasSpoiled )
{
2024-02-09 16:29:19 +01:00
toastMessage += "<br>(" + _ _t ( "Spoiled" ) + ")" ;
2019-12-19 12:48:36 -06:00
}
2025-01-10 17:15:09 +01:00
toastMessage += '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockBookingEntry(' + bookingResponse [ 0 ] . id + ',' + stockRowId + ', ' + bookingResponse [ 0 ] . product _id + ')"><i class="fa-solid fa-undo"></i> ' + _ _t ( "Undo" ) + '</a>' ;
2019-12-19 12:48:36 -06:00
Grocy . FrontendHelpers . EndUiBusy ( ) ;
2020-01-27 19:19:09 +01:00
RefreshStockEntryRow ( stockRowId ) ;
2020-01-17 10:54:34 -06:00
toastr . success ( toastMessage ) ;
2025-02-24 19:52:43 +01:00
Grocy . GetTopmostWindow ( ) . postMessage ( WindowMessageBag ( "BroadcastMessage" , WindowMessageBag ( "ProductChanged" , productId ) ) , Grocy . BaseUrl ) ;
2019-12-19 12:48:36 -06:00
} ,
function ( xhr )
{
Grocy . FrontendHelpers . EndUiBusy ( ) ;
console . error ( xhr ) ;
}
) ;
} ,
function ( xhr )
{
Grocy . FrontendHelpers . EndUiBusy ( ) ;
console . error ( xhr ) ;
}
) ;
} ) ;
$ ( document ) . on ( 'click' , '.product-open-button' , function ( e )
{
e . preventDefault ( ) ;
Grocy . FrontendHelpers . BeginUiBusy ( ) ;
var productId = $ ( e . currentTarget ) . attr ( 'data-product-id' ) ;
2020-01-21 17:30:09 +01:00
var specificStockEntryId = $ ( e . currentTarget ) . attr ( 'data-stock-id' ) ;
var stockRowId = $ ( e . currentTarget ) . attr ( 'data-stockrow-id' ) ;
2023-08-13 08:27:02 +02:00
var openAmount = Number . parseFloat ( $ ( e . currentTarget ) . attr ( 'data-open-amount' ) ) ;
2019-12-19 12:48:36 -06:00
var button = $ ( e . currentTarget ) ;
2020-08-29 16:41:27 +02:00
2023-08-13 08:27:02 +02:00
Grocy . Api . Post ( 'stock/products/' + productId + '/open' , { 'amount' : openAmount , 'stock_entry_id' : specificStockEntryId } ,
2019-12-19 12:48:36 -06:00
function ( bookingResponse )
{
2022-04-18 17:25:08 +01:00
Grocy . Api . Get ( 'stock/products/' + productId ,
function ( result )
{
button . addClass ( "disabled" ) ;
Grocy . FrontendHelpers . EndUiBusy ( ) ;
2025-01-10 17:15:09 +01:00
toastr . success ( _ _t ( 'Marked %1$s of %2$s as opened' , openAmount . toLocaleString ( { minimumFractionDigits : 0 , maximumFractionDigits : Grocy . UserSettings . stock _decimal _places _amounts } ) + " " + _ _n ( openAmount , result . quantity _unit _stock . name , result . quantity _unit _stock . name _plural , true ) , result . product . name ) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockBookingEntry(' + bookingResponse [ 0 ] . id + ',' + stockRowId + ', ' + productId + ')"><i class="fa-solid fa-undo"></i> ' + _ _t ( "Undo" ) + '</a>' ) ;
2022-04-18 17:25:08 +01:00
2022-08-27 11:27:49 +02:00
if ( result . product . move _on _open == 1 && result . default _consume _location != null )
2022-04-18 17:25:08 +01:00
{
toastr . info ( '<span>' + _ _t ( "Moved to %1$s" , result . default _consume _location . name ) + "</span> <i class='fa-solid fa-exchange-alt'></i>" ) ;
}
RefreshStockEntryRow ( stockRowId ) ;
2025-02-24 19:52:43 +01:00
Grocy . GetTopmostWindow ( ) . postMessage ( WindowMessageBag ( "BroadcastMessage" , WindowMessageBag ( "ProductChanged" , productId ) ) , Grocy . BaseUrl ) ;
2022-04-18 17:25:08 +01:00
} ,
function ( xhr )
{
Grocy . FrontendHelpers . EndUiBusy ( ) ;
console . error ( xhr ) ;
}
) ;
2019-12-19 12:48:36 -06:00
} ,
function ( xhr )
{
Grocy . FrontendHelpers . EndUiBusy ( ) ;
console . error ( xhr ) ;
}
) ;
} ) ;
2021-07-13 19:29:23 +02:00
$ ( document ) . on ( 'click' , '.stockentry-grocycode-label-print' , function ( e )
2021-06-12 17:21:12 +02:00
{
e . preventDefault ( ) ;
var stockId = $ ( e . currentTarget ) . attr ( 'data-stock-id' ) ;
Grocy . Api . Get ( 'stock/entry/' + stockId + '/printlabel' , function ( labelData )
{
if ( Grocy . Webhooks . labelprinter !== undefined )
{
Grocy . FrontendHelpers . RunWebhook ( Grocy . Webhooks . labelprinter , labelData ) ;
}
} ) ;
} ) ;
2020-01-27 19:19:09 +01:00
function RefreshStockEntryRow ( stockRowId )
2019-12-19 12:48:36 -06:00
{
2020-01-22 14:08:49 -06:00
Grocy . Api . Get ( "stock/entry/" + stockRowId ,
2019-12-19 12:48:36 -06:00
function ( result )
{
var stockRow = $ ( '#stock-' + stockRowId + '-row' ) ;
2020-01-23 19:13:35 +01:00
// If the stock row not exists / is invisible (happens after consume/undo because the undone new stock row has different id), just reload the page for now
if ( ! stockRow . length || stockRow . hasClass ( "d-none" ) )
{
window . location . reload ( ) ;
}
2020-08-29 16:41:27 +02:00
2019-12-19 12:48:36 -06:00
if ( result == null || result . amount == 0 )
{
2020-01-28 19:27:18 +01:00
animateCSS ( "#stock-" + stockRowId + "-row" , "fadeOut" , function ( )
2019-12-19 12:48:36 -06:00
{
2020-01-28 19:27:18 +01:00
$ ( "#stock-" + stockRowId + "-row" ) . addClass ( "d-none" ) ;
2019-12-19 12:48:36 -06:00
} ) ;
}
else
{
2020-11-15 19:53:44 +01:00
var dueThreshold = moment ( ) . add ( Grocy . UserSettings . stock _due _soon _days , "days" ) ;
2020-01-21 17:30:09 +01:00
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 ) )
{
2020-11-15 19:53:44 +01:00
if ( stockRow . attr ( "data-due-type" ) == 1 )
{
stockRow . addClass ( "table-secondary" ) ;
}
else
{
stockRow . addClass ( "table-danger" ) ;
}
2020-01-21 17:30:09 +01:00
}
2020-11-15 19:53:44 +01:00
else if ( bestBeforeDate . isBefore ( dueThreshold ) )
2020-01-21 17:30:09 +01:00
{
stockRow . addClass ( "table-warning" ) ;
}
2025-01-16 21:34:01 +01:00
animateCSS ( "#stock-" + stockRowId + "-row td:not(:first)" , "flash" ) ;
2019-12-19 12:48:36 -06:00
2020-01-28 19:27:18 +01:00
$ ( '#stock-' + stockRowId + '-amount' ) . text ( result . amount ) ;
2020-11-15 19:53:44 +01:00
$ ( '#stock-' + stockRowId + '-due-date' ) . text ( result . best _before _date ) ;
$ ( '#stock-' + stockRowId + '-due-date-timeago' ) . attr ( 'datetime' , result . best _before _date + ' 23:59:59' ) ;
2019-12-19 12:48:36 -06:00
2020-01-28 19:27:18 +01:00
$ ( ".stock-consume-button" ) . attr ( 'data-location-id' , result . location _id ) ;
2020-01-22 14:08:49 -06:00
2020-01-17 10:54:34 -06:00
var locationName = "" ;
Grocy . Api . Get ( "objects/locations/" + result . location _id ,
function ( locationResult )
{
locationName = locationResult . name ;
2020-03-25 20:00:52 +01:00
$ ( '#stock-' + stockRowId + '-location' ) . attr ( 'data-location-id' , result . location _id ) ;
$ ( '#stock-' + stockRowId + '-location' ) . text ( locationName ) ;
2020-01-17 10:54:34 -06:00
} ,
function ( xhr )
{
console . error ( xhr ) ;
2020-01-21 17:30:09 +01:00
}
) ;
2020-08-29 16:41:27 +02:00
2022-04-02 17:49:35 +02:00
Grocy . Api . Get ( "stock/products/" + result . product _id ,
function ( productDetails )
{
2023-02-06 20:22:10 +01:00
if ( ! result . price )
2022-04-18 18:42:40 +02:00
{
result . price = 0 ;
}
2023-02-06 20:22:10 +01:00
$ ( '#stock-' + stockRowId + '-price' ) . text ( _ _t ( "%1$s per %2$s" , ( result . price * productDetails . qu _conversion _factor _purchase _to _stock ) . toLocaleString ( undefined , { style : "currency" , currency : Grocy . Currency , minimumFractionDigits : Grocy . UserSettings . stock _decimal _places _prices _display , maximumFractionDigits : Grocy . UserSettings . stock _decimal _places _prices _display } ) , productDetails . default _quantity _unit _purchase . name ) ) ;
$ ( '#stock-' + stockRowId + '-price' ) . attr ( "data-original-title" , _ _t ( "%1$s per %2$s" , result . price . toLocaleString ( undefined , { style : "currency" , currency : Grocy . Currency , minimumFractionDigits : Grocy . UserSettings . stock _decimal _places _prices _display , maximumFractionDigits : Grocy . UserSettings . stock _decimal _places _prices _display } ) , productDetails . quantity _unit _stock . name ) ) ;
2025-01-19 14:57:19 +01:00
if ( productDetails . product . disable _open == 1 )
{
$ ( ".product-open-button[data-stockrow-id='" + stockRowId + "']" ) . addClass ( "disabled" ) ;
}
2022-04-02 17:49:35 +02:00
} ,
function ( xhr )
{
console . error ( xhr ) ;
}
) ;
2022-03-30 17:32:53 +02:00
$ ( '#stock-' + stockRowId + '-note' ) . text ( result . note ) ;
2020-01-28 19:27:18 +01:00
$ ( '#stock-' + stockRowId + '-purchased-date' ) . text ( result . purchased _date ) ;
2020-01-21 17:30:09 +01:00
$ ( '#stock-' + stockRowId + '-purchased-date-timeago' ) . attr ( 'datetime' , result . purchased _date + ' 23:59:59' ) ;
2023-02-06 20:22:10 +01:00
if ( result . shopping _location _id )
2022-04-18 18:42:40 +02:00
{
var shoppingLocationName = "" ;
Grocy . Api . Get ( "objects/shopping_locations/" + result . shopping _location _id ,
function ( shoppingLocationResult )
{
shoppingLocationName = shoppingLocationResult . name ;
$ ( '#stock-' + stockRowId + '-shopping-location' ) . attr ( 'data-shopping-location-id' , result . location _id ) ;
$ ( '#stock-' + stockRowId + '-shopping-location' ) . text ( shoppingLocationName ) ;
} ,
function ( xhr )
{
console . error ( xhr ) ;
}
) ;
}
else
{
$ ( '#stock-' + stockRowId + '-shopping-location' ) . text ( "" ) ;
}
2020-03-25 20:00:52 +01:00
2020-01-28 19:27:18 +01:00
if ( result . open == 1 )
2020-01-21 17:30:09 +01:00
{
2025-01-14 17:54:06 +01:00
$ ( '#stock-' + stockRowId + '-opened-amount' ) . text ( _ _n ( result . amount , 'Opened' , 'Opened' ) ) ;
2020-01-28 19:27:18 +01:00
}
else
{
$ ( '#stock-' + stockRowId + '-opened-amount' ) . text ( "" ) ;
$ ( ".product-open-button[data-stockrow-id='" + stockRowId + "']" ) . removeClass ( "disabled" ) ;
}
2019-12-19 12:48:36 -06:00
}
2020-01-21 17:30:09 +01:00
// Needs to be delayed because of the animation above the date-text would be wrong if fired immediately...
2019-12-19 12:48:36 -06:00
setTimeout ( function ( )
{
2020-01-27 19:00:49 +01:00
RefreshContextualTimeago ( "#stock-" + stockRowId + "-row" ) ;
RefreshLocaleNumberDisplay ( "#stock-" + stockRowId + "-row" ) ;
2025-01-31 15:35:34 +01:00
} , Grocy . FormFocusDelay ) ;
2019-12-19 12:48:36 -06:00
} ,
function ( xhr )
{
Grocy . FrontendHelpers . EndUiBusy ( ) ;
console . error ( xhr ) ;
}
) ;
}
$ ( window ) . on ( "message" , function ( e )
{
var data = e . originalEvent . data ;
2025-01-11 12:06:15 +01:00
if ( data . Message == "ProductChanged" )
2025-01-10 17:15:09 +01:00
{
2025-01-16 21:34:01 +01:00
$ ( ".stock-consume-button[data-product-id='" + data . Payload + "']" ) . each ( function ( )
{
RefreshStockEntryRow ( $ ( this ) . attr ( "data-stockrow-id" ) ) ;
} ) ;
} ;
2019-12-19 12:48:36 -06:00
} ) ;
2020-01-17 10:54:34 -06:00
2020-01-22 14:08:49 -06:00
Grocy . Components . ProductPicker . GetPicker ( ) . trigger ( 'change' ) ;
2025-01-10 17:15:09 +01:00
function UndoStockBookingEntry ( bookingId , stockRowId , productId )
2020-01-17 10:54:34 -06:00
{
2020-08-30 12:18:16 +02:00
Grocy . Api . Post ( 'stock/bookings/' + bookingId . toString ( ) + '/undo' , { } ,
2020-01-17 10:54:34 -06:00
function ( result )
{
2025-02-24 19:52:43 +01:00
Grocy . GetTopmostWindow ( ) . postMessage ( WindowMessageBag ( "BroadcastMessage" , WindowMessageBag ( "ProductChanged" , productId ) ) , Grocy . BaseUrl ) ;
2020-01-17 10:54:34 -06:00
toastr . success ( _ _t ( "Booking successfully undone" ) ) ;
} ,
function ( xhr )
{
console . error ( xhr ) ;
}
) ;
} ;