Inventory Adjustments data location

Understood - thank you for that info.

Looking through the LogEntryList object, I am still confused. Here is my approach:

I obtain a collection of all StockedProductAdjustments where the ProductType is ‘Product’. I know that it populates the collection with several hundred records. My intent is to loop through this, retrieve the LogEntryList, see which have changed since our process last ran, and run them through the integration to our accounting system.

However, when I attempt to loop through and get the LogEntryList for each StockedProductID (as you indicated above), I never get any results. The LogEntryList list object instance is always empty.

Can you please clarify exactly how I am supposed to do this? Simply retrieving all records by using:
LogEntryList.GetLogEntryList(LogEntry.ChildTypes.StockedProduct) does not work (unless I am missing something), because there is no ‘ID’ field in the LogEntryList entries to link out to the StockedProduct in question.

Here is my code snippet:

//***** Loop through all Adjustments *****
StockedProductAdjustmentCollection all_adjustments = StockedProductAdjustmentCollection.GetStockedProductAdjustmentCollection(ProductType.Product);
foreach (StockedProductAdjustment myAdjustment in all_adjustments)
//***** Need to use log entry list object for versioning of adjustments *****
LogEntryList logAdjustments = LogEntryList.GetLogEntryList(myAdjustment.StockedProductID);
if (logAdjustments.Count > 0)
//Do something

Thanks for your continued assistance with this,

To answer your question as well, I would like to see VersionStamp added for StockedProducts as well, to maintain consistency in our code. It would be necessary if the LogEntryList object isn’t able to work for my scenario.

If you need me to provide more reasons why VersionStamp would help us in order to get it added, let me know and I can provide them.

Hi Alex.

StockedProductAdjustmentCollection retrieves product data as expected by specific UI components, you may be able to give it miss for the purpose of checking changes.

An adjustment performed in Quantify UI using ‘Adjust quantities for the selected location’ when successfully completed should result in StockedProduct data being modified and adding entry in LogEntryList

Changes/updates to products for a location may be checked for as below…

            bool stockedProductUpdatedAtLocation = false;
            LogEntryList logs = LogEntryList.GetLogEntryList(STOCKING_LOCATION_ID);
            if (logs.Count(log => log.LogDate >= DateTime.Now.Date) > 0)
                stockedProductUpdatedAtLocation = true;

However, the above does not get change-info for each part/product at the location; this will be available through VersionStampList in the upcoming release.


Got it, thank you very much for the clarification and quick response.

Is it possible to get that change added into our hot fix version of Quantify that you guys were able to get us a few days ago? (see this thread for more details:

This is another one of those data entities where we need that versioned information in order to be able to integrate with our accounting system - there isn’t really a workaround.

Alternatively, if the upcoming release will be within the next week, then we can probably wait for the full release.

Let me know what you think when you have a chance.
Thanks so much,

Hi Alex.

We shall post today’s EOD build here, which includes the VersionStamp on StockedProduct.

Thanks for posting.

Please find the URL to pre-QA build below -

Quantifyx64.exe (90.4 MB)

It may be required to login once to apply secured changes. Also, for the API applications, it may be required to refresh the Library DLL


Thank you so much for the very quick turnaround for this new code. This update resolved the InvoiceCollection.GetInvoiceCollection error I ran into, however I am unable to find the VersionStamp field on StockedProducts. Can you please provide me some guidance on exactly where this should be?

I looked on the following objects, and the VersionStamp field is not there:

Am I missing something obvious? Also, I did notice that the Avontus.Core DLL did not change when we ran our update - is this expected or could that be the culprit?

The versions for each of the DLLs that we have are as follows:
Avontus.Core -
Avontus.Quantify.Reports - 8.3.1460.125
Avontus.Rental.Library - 8.3.1460.125
Avontus.Rental.Utility - 8.3.1460.125

Let me know if you need more info from me on this, and thanks again so much for your help.


Hi Alex.

Currently this is included in the dedicated VersionStampList object as below, you can expect it to be added to StockedProductListItem in the future releases.

VersionStampList stockedProductVersions = VersionStampList.GetVersionList(VersionStampList.DataObjectName.StockedProduct);
foreach (var item in stockedProductVersions)
   Debug.WriteLine($"StockedProductID: {item.Key} Version: {item.Value}");

Thanks for posting.

Ah, I see - that makes sense. I should be able to make that work in that case.

Hopefully final question then on this - it looks like I am not using the necessary reference yet to access the VersionStampList object. Where is this object located?

I am using the following references as of now:
using Avontus.Core;
using Avontus.Rental.Library;
using Avontus.Rental.Library.Accounting;
using Avontus.Rental.Library.Accounting.XeroAccounting;
using Avontus.Rental.Library.Security;
using Avontus.Rental.Library.ToolWatchImport;
using Avontus.Rental.Library.Logging;
using Avontus.Rental.Library.Database;

Thanks so much,

Hi Alex.

Please note that VersionStampList class is under Avontus.Rental.Library.Utility namespace.

using Avontus.Rental.Library.Utility;

The VersionStampList utility class takes VersionStampList.DataObjectName as parameter, which is synonymous to the table in database, and lists (Primary-Key-ID, VersionStamp) for the entire table in an efficient manner.

Thanks for posting.


Excellent, thank you for the info on where that was. I was able to access it and write my code accordingly to look at the VersionStamps of the StockedProducts.

I have one question regarding the data in the StockedProduct object, however - I ran my code in debug mode and noticed that after an adjustment is made (using ‘adjust quantities’ for a location), the ChangeQuantity field never gets populated, and further the ‘QtyForRentOriginal’ and ‘QuantityForRent’ fields are both equal to the new quantity value, after the change was made (this is the same for the ‘QtyNewOriginal’ and ‘QuantityNew’, if referring to New quantities vs. Available quantities).

Seeing this I am confused how I would go about identifying how much the quantity actually changed. Is this supposed to be going into the ‘ChangeQuantity’ field, or is the original value supposed to be going into the Qty…Original field? Or is this just not how it works, and I am going about this incorrectly?

Thanks again for your continued assistance with this.

Additionally, I need to be able to identify if a StockedProduct’s quantity has been changed due to something other than the ‘Adjust quantities’ functionality (e.g. from a Movement).

Is the only way to do this by looking at the fields in the StockedProduct object such as ‘QuantityOnOrder’, ‘QuantityOnOrderNew’, etc. to see if they have a value, and if they do not have a value, then the StockedProduct’s quantity was adjusted via ‘Adjust quantities’?


Hi Alex.

Stocked product objects and tables are designed only to hold the current value for quantities. “Original” properties are meant for only for holding original values, in case of an edit, till the time it is saved to database. Only the current values are accessible using stocked product objects as below -

            StockedProductList stockedProductsBranch = StockedProductList.GetSerializedStockedProductList(LOC_ID, Guid.Empty);
            foreach (var item in stockedProductsBranch)
                Console.WriteLine($"For Rent - {item.QuantityForRent} In Transit - {item.QuantityInTransit} New - {item.QuantityNew} Discrepancy - {item.QuantityReserved}");

The history of changes, including the previous values, are not directly accessible from stocked product or related objects. A workaround, inside of Quantify, would be to obtain it from log entries as below. Since LogEntryListItem caters to textual logs the Product-ID is not exposed in the object, but the ID is still captured in the database. If it is useful I can place a request to expose Product-ID in the log items.

    LogEntryList logs = LogEntryList.GetLogEntryList(LOC_ID);
    foreach (var item in logs.Where(log => log.LogDate >= DateTime.Today).OrderByDescending(log => log.LogDate))
        Console.WriteLine($"Change    - {item.Name} \r\nPart      - {item.ChildDescription} \r\nOld Value - {item.OldValue} \r\nNew Value - {item.NewValue} \r\n\r\n");

Thanks for posting.

Thank you for getting back to me on this quickly.

This is interesting - but I think I understand the requirements.

I have one question and one comment to identify if this will be able to work for us:

  1. For the ‘item.Name’ field, I see options of ‘New Part Changed’ and ‘For Rent Part Changed’. Are these two options encapsulating for what I need to do, i.e. identify all instances where part quantities were adjusted using ‘Adjust products’? If not, can you please send a list of all the item.Name options I should be checking for in my code?

  2. I think the Product ID being included in the log items for these types of LogEntryList records is necessary to ensure this works, since we will need to identify which LogEntryList item corresponds to which StockedProductAdjustment object. To clarify on that as well - that would correspond to the ‘StockedProduct.BaseProductID’ field, correct?

Thanks again for the assistance, I think we are very close to a potential solution with this.


Hi Alex.

The log entry names, in this context, takes the following values depending on the quantity type that was adjusted, this is a logging feature that might provide a workaround, if it proves inadequate it may become necessary to save old quantities outside of Quantify -

  • For Rent Part Changed
  • Reserved Part Changed
  • Discrepancy Part Changed
  • In Transit Part Changed
  • New Part Changed
  • For Rent Part Added
  • Reserved Part Added
  • Discrepancy Part Added
  • In Transit Part Added
  • New Part Added

correspond to the ‘StockedProduct.BaseProductID’ field, correct?

That is correct, however, in the above example I’ve used StockedProductList instead of StockedProductAdjustment as latter is primarily designed as a command/action class for adjustments.

Thanks for posting.


Sounds good, thank you for providing that list.

More questions now, as I am getting into debugging through the API and learning the intricacies of LogEntryList.

  1. When I look in the SQL LogEntryList table, there is an option for item.Name called ‘Available Part Changed’. Is this analogous to For Rent Part Changed? I am confused on the distinction.

For my second question, some background first:

I was able to identify my exact records that came from my adjustments via SQL by looking only for ‘New Part Changed’ and ‘Available Part Changed’ for the Name field in the LogEntryList table. It appears this Name is used if and only if the records came from an Adjustment via ‘Adjust quantities’, which is excellent news if I am right.

I set out to use the API to obtain those records that correspond to the adjustments via the following code:

LogEntryList myStockedProductLogs = LogEntryList.GetLogEntryList(LogEntry.ChildTypes.StockedProduct);

if (myStockedProductLogs.Any(item => item.Name == “New Part Changed” && item.ChildDescription.Split(separatorString, StringSplitOptions.RemoveEmptyEntries)[0] == myAdjustment.PartNumber))
var myAdjustmentLog = myStockedProductLogs.First(item => item.Name == “New Part Changed” && item.ChildDescription.Split(separatorString, StringSplitOptions.RemoveEmptyEntries)[0] == myAdjustment.PartNumber);
var changedQuantity = Int32.Parse(myAdjustmentLog.NewValue) - Int32.Parse(myAdjustmentLog.OldValue);
myTransLine.quantity = changedQuantity.ToString();

This fortunately returns my expected records, although it is a bit clunky with the string splitting going on to get at the Part Number. Nevertheless, it works consistently, unless I change the criteria to look for “Available Part Changed”. Then, it crashes with an “Index out of Bounds of Array” error, even though I expect to find records for that criteria, since it is clearly in the SQL table for those Parts (and even if I don’t find any, my List.Any() method shouldn’t crash, it should simply return no values).

So, my question is -

  1. Am I going about searching for adjustments of Available part quantities the right way with the code above (just replace “New” with “Available” in the criteria)? Do you have any advice on why it may be crashing?

In the meantime I will see if it is somehow a bug in my code.

Thanks so much, this time we are very close.


I have resolved this - it looks as though the StringSplitOptions.RemoveEmptyEntries was the culprit. I changed it to StringSplitOptions.None and it worked.

As a final note, this appears it will work for us, however I think it would be cleaner eventually to have the ProductID available on these types of LogEntryListItems. We do not need a hotfix for this as of now, but this would be very nice to see in the next release.

Thanks again for all your help with this one, this was quite the learning experience.

All the best,

Update -

In the upcoming release, additional properties have been exposed in LogEntryListItem object that may be used as in the below example.

            LogEntryList logs = LogEntryList.GetLogEntryList(LOC_ID);
            foreach (var item in logs.Where(log => log.LogDate >= DateTime.Today).OrderByDescending(log => log.LogDate))
                Console.WriteLine($"Change - {item.Name}\r\nStockingLocationID - {item.ParentID} \r\nBaseProductID - {item.ChildID} \r\nOldValue - {item.OldValue} \r\nNewValue - {item.NewValue} \r\n");

Note - please ensure that the point/pre-QA releases are completely uninstalled before installing the production/public release.


Thanks so much for getting back to me on this. This is good news this will be available in the upcoming release.

A question related to the upcoming release (feel free to make another thread since this is about the release itself) - when exactly will this be available, if it is not already?

I am asking because during our development/testing we have used a few point/pre-QA releases in order to accomplish what we needed. However, we are looking to roll out our integration in a Production capacity on November 2nd, 2020. Will the new release be available by then?

If not, is it possible to obtain a working version of the release that we could use in the interim? This Production roll out is a hard deadline set by our company, we will not be able to move it unless there are extenuating circumstances preventing us from being able to roll out.

Please let me know when you have a chance, or if you have any questions regarding our rollout plan or exactly which point releases we have used thus far.

Thanks so much,

Hi Alex.

The upcoming public release for Quantify is scheduled for 20th of this month .

Thanks for posting.