Product showing as out of stock even if not active

Hi,

I have 2 products that keeps saying ‘out of stock’ on the dashboard.

I’ve tried deleting the product but that was not allowed. So I deactivated them, still showing up. I tried deleted the inventory levels, same thing… still showing up.

Help! haha :slight_smile:

Can you show me the Stock History for each of those products?

Any suggestions on how to actually deactivate a product? The product is already inactive but is still listed in reports.

You can mark them as not supported on the inventory level screen. Edit product>Inventory Levels tab>Create stock level>Choose not supported and create.

That should work, although it might depend on the version. Worth noting that 0.9.5, which is coming out in summer 2025, will contain an update to this indicator to filter the out of stock and make it more useful.

Also please consider filling out our quick community survey so that we can better understand your implementation and your needs! Microsoft Forms

It had no effect. In Reporting > Inventory By Location Report the inactive product continues to appear.

This is likely an issue with the behavior of that report. It probably wasn’t built to filter out those lines. If you are a software developer or have access to one, Justin might be able to advise you how to apply criteria to the report.

OK thanks. @jmiranda, can you give an idea of ​​how to filter so as not to list inactive products?

Sorry for the late response. I assume we’ll need to make a code change for this.

Is there a way, at this moment, to disable showing products in a warehouse that have 0 stock but don’t need no longer stock for this warehouse?

As example, above product was in stock in that warehouse, but doesn’t need to be in stock in that warehouse anymore, but in others. But it keeps showing 0 / not in stock.

From within the application, I don’t think there’s a way to do it, but I agree that there should be. You should be able to delete products and have that cascade throughout the application (order items, shipment items, etc). However, we also have tables that have been derived using that data (product_availability, product_demand, reporting fact tables) so the feature required to delete a product is much more involved and complex than it might appear.

There’s actually one way to make a product “disappear” within the application. You can merge a product into another product if this is indeed a duplicate product. If it’s not, I would discourage the use of the product merge feature.

Within the database, you can delete the product assuming you delete all of the records within tables that reference that product_id (including but not limited to inventory_item, shipment_item, transaction_entry, order_item, product_dimension, product_availability, etc). The problem is that it’s difficult to figure out the ordering of deletes to make this less frustrating. But you could do it.

You could also disable foreign key checks and attempt to delete the product and all of its references, but you’ll probably run into some weird behavior at some point if you miss some of the referential data i.e. when you open a shipment that still has a foreign key to the deleted product. So I would avoid that until you identify and delete all of the reference data.

Here’s a query to return all database objects related to the

SELECT tables.table_schema as database_name, tables.table_name, tables.table_type 
FROM information_schema.columns  
JOIN information_schema.tables ON (information_schema.columns.table_schema = information_schema.tables.table_schema  
AND information_schema.columns.table_name = information_schema.tables.table_name)
WHERE column_name IN ('product_id') 
AND tables.table_schema = 'openboxes' 
# AND tables.table_type = 'BASE TABLE'
ORDER BY tables.table_name;

NOTE: I wanted to provide a query that returns all objects, but you can uncomment the table_type clause to return only database objects that contain data i.e. table_type = ‘BASE TABLE’.

And, here are the query results run against a development version of the database.

NOTE: This is a development database so you might see some tables here that you don’t see in your database. Therefore focus on your own query results.

+---------------+---------------------------------+------------+
| database_name | table_name                      | table_type |
+---------------+---------------------------------+------------+
| openboxes     | consumption                     | BASE TABLE |
| openboxes     | cycle_count_request             | BASE TABLE |
| openboxes     | cycle_count_session             | VIEW       |
| openboxes     | edit_page_item                  | VIEW       |
| openboxes     | fill_rate                       | VIEW       |
| openboxes     | inventory_item                  | BASE TABLE |
| openboxes     | inventory_level                 | BASE TABLE |
| openboxes     | inventory_snapshot              | BASE TABLE |
| openboxes     | invoice_item                    | BASE TABLE |
| openboxes     | on_order_order_item_summary     | VIEW       |
| openboxes     | on_order_shipment_item_summary  | VIEW       |
| openboxes     | on_order_summary                | VIEW       |
| openboxes     | order_item                      | BASE TABLE |
| openboxes     | order_item_details              | VIEW       |
| openboxes     | order_item_summary              | VIEW       |
| openboxes     | product_association             | BASE TABLE |
| openboxes     | product_attribute               | BASE TABLE |
| openboxes     | product_availability            | BASE TABLE |
| openboxes     | product_availability_computed   | BASE TABLE |
| openboxes     | product_catalog_item            | BASE TABLE |
| openboxes     | product_category                | BASE TABLE |
| openboxes     | product_demand                  | VIEW       |
| openboxes     | product_demand_details          | BASE TABLE |
| openboxes     | product_demand_details_tmp      | BASE TABLE |
| openboxes     | product_dimension               | BASE TABLE |
| openboxes     | product_document                | BASE TABLE |
| openboxes     | product_expiry_summary          | VIEW       |
| openboxes     | product_group_product           | BASE TABLE |
| openboxes     | product_inventory_compare_view  | VIEW       |
| openboxes     | product_inventory_expiry_view   | VIEW       |
| openboxes     | product_inventory_extended_view | VIEW       |
| openboxes     | product_inventory_pivot_view    | VIEW       |
| openboxes     | product_inventory_snapshot_view | VIEW       |
| openboxes     | product_package                 | BASE TABLE |
| openboxes     | product_snapshot                | VIEW       |
| openboxes     | product_stocklist               | VIEW       |
| openboxes     | product_stockout                | VIEW       |
| openboxes     | product_stockout_status         | VIEW       |
| openboxes     | product_substitution_status     | VIEW       |
| openboxes     | product_summary                 | VIEW       |
| openboxes     | product_supplier                | BASE TABLE |
| openboxes     | product_supplier_clean          | VIEW       |
| openboxes     | product_tag                     | BASE TABLE |
| openboxes     | receipt_item                    | BASE TABLE |
| openboxes     | requirement                     | VIEW       |
| openboxes     | requisition_item                | BASE TABLE |
| openboxes     | shipment_item                   | BASE TABLE |
| openboxes     | stocklist_item_list             | VIEW       |
| openboxes     | stock_movement_item             | VIEW       |
| openboxes     | substitution_item               | VIEW       |
| openboxes     | synonym                         | BASE TABLE |
| openboxes     | transaction_entry               | BASE TABLE |
+---------------+---------------------------------+------------+
52 rows in set (0.020 sec)

There are some potentially complex associations between a lot of these tables. For example, inventory_item references product_id and lots of other tables reference inventory_item_id alone or sometimes both product_id and inventory_item_id. So you might need to find all of the records that contain a reference to the product itself or one of its inventory items.

Once you have the list, report back here and I can provide further instructions. I would also strongly recommend creating a database backup before you start this exercise just in case.

By the way, here’s an older ticket that explains the reason for not allowing users to delete products and suggests an alternative. The alternative is much harder to implement than the hard delete so I might think about creating a ticket for hard delete that is accessible to the superuser role.

Thnx for the follow-up. Problem is that I don’t want to delete a product in total but only not showing as 0 (zero) stock in some warehouses if they are depleted and no longer in use in that warehouse.

As far as I know, the products showing up in that report are included because there are transactions in that particular location for that product. I’ll check the code to verify that is true. If that’s the case they only way to remove those products from those reports is to remove the transactions against those products in that location.

At least that is how we intended to build that particular report, if I’m not mistaken. If I’m wrong about that then this would require a bug fix. In addition, if a product is inactive, theoretically, it should not show up anywhere in the system. However, the inactive filter probably hasn’t been applied across all features and reports. I think when we first implemented the inactive flag (for product), the most important features for excluding these products were the Product Search and Global Search.

There’s a feature within the system called Inventory Level status that allows you to mark a product Supported vs Not Supported for a given location. This worked with the legacy dashboard and some reports, but I don’t think is used across newer features. I think there’s a plan to resurrect / refactor the Inventory Level feature in the near future, but we’ll try to get to the bottom of this ahead of that.