Skip to content

OBPIH-7437 handle all items skipped during inventory import#5431

Merged
ewaterman merged 1 commit intorelease/0.9.5from
bug/OBPIH-7437-handle-empty-import
Aug 6, 2025
Merged

OBPIH-7437 handle all items skipped during inventory import#5431
ewaterman merged 1 commit intorelease/0.9.5from
bug/OBPIH-7437-handle-empty-import

Conversation

@ewaterman
Copy link
Member

✨ Description of Change

Link to GitHub issue or Jira ticket: https://pihemr.atlassian.net/browse/OBPIH-7437

Description: If an import has no products/items or all the items are skipped due to no quantity being defined, ALL products for the facility were getting zeroed out. This was due to how a query in InventoryService was working (if the given list of products is falsey, fetch ALL transactions).

A more proper fix would be to change the query to distinguish between an empty list of products and a null list of products, but that refactor would have potential knock on effects across users of that query so I opted for the safest option for now since we're so close to release.


📷 Screenshots & Recordings (optional)

Video describing issue: https://jam.dev/c/732d4448-6805-4bbc-9c8f-ef2314d2965c

@ewaterman ewaterman requested a review from kchelstowski August 5, 2025 18:24
@ewaterman ewaterman self-assigned this Aug 5, 2025
@github-actions github-actions bot added type: bug Addresses unintended behaviours of the app domain: backend Changes or discussions relating to the backend server labels Aug 5, 2025
// TODO: Consider refactoring this logic to distinguish between products==null and products.?isEmpty().
// The former should give the current behaviour (fetch ALL products) and the latter should return an
// empty list. Existing flows will need to be refactored to default to either passing null or []
// depending on their desired behaviour. See OBPIH-7437.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said in the PR description, a more proper fix would be to change this query to distinguish between an empty list of products and a null list of products. However since we're so close to release I didn't want to break anything else in the system that uses this method so I opted to just put a TODO in for now and fixed it directly for inventory imports only.

// in InventoryService.getTransactionEntriesBeforeDate is resolved, this will no longer be true.)
if (!inventoryImportData.products) {
return
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if it handles all cases. As far as I'm concerned, we could have X items filled properly and leave only one item blank, and this would make every product to have quantities zeroed out.
If I read the code properly, you only handle a case when you have all items empty.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you say more about why you feel that way?

Any rows/items that are left blank are not included in inventoryImportData.products:

private InventoryImportData parseData(ImportDataCommand command) {
    InventoryImportData inventoryImportData = new InventoryImportData()
    for (def row in command.data) {
        // We've already warned the user during the validation step about any rows with a null QoH, so if there
        // are any that are still null at this point, simply ignore them.
        if (row.quantity == null) {
            continue
        }
    ...

If all rows are empty we get into the situation fixed by this ticket, but if only some of the items are empty and others set a quantity, then inventoryImportData.products will not be empty, and the if (products) condition in InventoryService.getTransactionEntriesBeforeDate will be true, and so it will fetch only the transaction entries for the given products.

List<TransactionEntry> getTransactionEntriesBeforeDate(Location facility, Collection<Product> products, Date date) {
    def criteria = TransactionEntry.createCriteria()
    return criteria.list {
        if (products) {
            inventoryItem {
                'in'("product", products)
            }
        }
        transaction {
            ...
        }
    } as List<TransactionEntry>
}

We use the result of this query to build ProductAvailability records (it does a call to inventoryService.getQuantityAsAvailableItems(transactionEntries)).

We then later only zero out any items whose products were in the import but didn't have a row for their specific item (can happen if a product is in multiple bins/lots and we only import one of those bins/lots):

// For all products in the import, any other bins/lots of those products that exist in the system (ie have
// a product availability entry) but were not in the import should have their quantity set to zero.
Set<String> keysInImport = inventoryImportData.rows.keySet()
for (entry in availableItems) {
    AvailableItem availableItem = entry.value

    if (keysInImport.contains(entry.key)) {
        continue
    }

    TransactionEntry transactionEntry = new TransactionEntry(
            transaction: transaction,
            quantity: -availableItem.quantityOnHand,
            product: availableItem.inventoryItem.product,
            binLocation: availableItem.binLocation,
            inventoryItem: availableItem.inventoryItem,
            comments: 'Item was not in inventory import file so quantity was assumed to be zero.',
    )
    transaction.addToTransactionEntries(transactionEntry)
}

Remember that in the above code, availableItems only contains data for the products that were imported, not ALL availableItems.

Maybe you're seeing something that I'm not, but I recorded a video demonstrating the behaviour: Screencast from 2025-08-06 08:29:14 AM.webm

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I trust you. I just remember I ran into that edge case when I had a few lines filled properly and probably one line not filled.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm I tried again to reproduce it a few different ways with some lines filled out and others not but it always worked correctly after this fix. I'll merge the change in as is but we can keep an eye on it. Thanks for the review

@ewaterman ewaterman merged commit 02f1ed6 into release/0.9.5 Aug 6, 2025
5 checks passed
@ewaterman ewaterman deleted the bug/OBPIH-7437-handle-empty-import branch August 6, 2025 20:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain: backend Changes or discussions relating to the backend server type: bug Addresses unintended behaviours of the app

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants