Problem/Motivation
Refer to the general discussion/brainstorm about inventory management here: #2401531: [META] Farm Inventory Brainstorm/Discussion
This issue is specifically for the implementation of a Farm Inventory module that provides the ability to record asset inventory adjustments alongside log entries, similar to the way that Movements work (http://farmos.org/guide/location/).
Proposed resolution
Add an "Inventory" field collection to various log types (similar to the Movement field collection for tracking location), with the following sub-fields:
- Asset (entity reference) - to indicate which asset the inventory adjustment is being made to
- Value (fraction) - to define the amount of inventory adjustment
Logs should allow multiple inventory adjustments to be made to different assets. This can be achieved by making the inventory field collection instance allow multiple ("unlimited") values.
To determine the current inventory level of an asset, the system would look back at all logs that have an inventory adjustment assigned to the asset. Only logs that are "done" with a "timestamp" less than or equal to the present moment will be included, similar to the way that location is determined (it should also be possible to pass a timestamp and get inventory levels at a specific time in the past/future). An asset's current inventory should be displayed on the asset view page (/farm/asset/%(/view)).
Custom Views handlers will be necessary for displaying current inventory levels in Views. The custom handler for determining an asset's current location can be used as a guide, but we will also need to perform a SUM aggregation in the database query.
Not all asset types will need to have inventory tracking available. A new database table will be created that stores inventory settings for each asset type, including whether or not inventory is enabled.
There will be a need to differentiate the "default" inventory of certain asset types. For example, if you create a new Animal asset, and do not specify any inventory on it, then we should assume that it represents an "individual" animal. For the purposes of tallying, this will mean that the asset has an inventory of 1, even if it doesn't have any inventory adjustment logs. On the contrary, we will want to have other asset types default their inventory to 0. For example, if we add assets in the future for tracking seed stock, feed stock, or other bulk materials, they should have a default inventory of 0, and require that you add inventory adjustment logs in order to increase/decrease them. Thus, one of the settings associated with asset types should be a boolean indicating whether or not we should treat assets as "individuals" by default.
Only "Animal" asset types will have inventory management enabled at first, to enable head counts. It won't be hard to add additional asset types as a follow-up for tracking things like seed stock, inputs, etc. We can create follow-up feature requests for those separately. This issue is just for the underlying inventory module that will make it all possible.
Remaining tasks
Create new Farm Inventory module (farm_inventory).Add an Inventory field collection with sub-fields: Asset and Value.Add Inventory field collection to log types: Input, Activity, Harvest, Seeding, Transplanting, Medical, Observation, Sale, Maintenance.Add function for calculating an asset's inventory: farm_inventory() and farm_inventory_query().Display asset inventory on asset view pages (only if inventory is enabled for the asset type).Add a {farm_inventory_asset_type} database table for storing asset type inventory settings.Implement hooks for entity load, insert, update, and delete to maintain asset type inventory settings.Alter asset type form to show inventory settings.Add functions that check if inventory management is enabled on an asset, and whether or not to treat an asset as an individual by default.Only display inventory if it is enabled for assets.Default the inventory of "individual" assets to 1.Add a View of "logs with inventory adjustments".Show "logs with inventory adjustments" on asset pages.Add Views integration for {farm_inventory_asset_type} table.Add a function that returns a list of asset types with inventory enabled.Add custom Views asset type filter handler that only includes types with inventory enabled.Create an Entity Reference View for selecting assets that have inventory enabled.Use farm_inventory_entityreference_view for selecting assets in inventory adjustment.Add a function for programatically creating a log that sets the current inventory level.Add an Inventory field to asset edit form that allows setting the current inventory (via programatic log creation).Create function for formatting inventory values.Add Views field handler for asset inventory value.
User interface changes
Logs will have a new "Inventory" tab that provides user's with the ability to add inventory adjustments to the log. It will be a multi-value field so more than one adjustment can be added. Each adjustment will reference an asset, and will have a value that can be positive (to record an increase in the asset's inventory) or negative (to record a decrease in the asset's inventory).
Asset type edit forms will expose inventory settings for "enabled" (to enable inventory management for the asset type), and "individual" (to specify that assets of this type should be treated as individuals if they do not have any inventory adjustments).
When editing assets (that have inventory tracking enabled), an "Inventory" field will be available to specify the asset's current inventory level. This will automatically generate an observation log - just like the "Location" field that currently acts as a shortcut for creating movements.
A new Views field handler will be available for displaying inventory in asset lists.
API changes
New functions:
farm_inventory(FarmAsset $asset, $time = REQUEST_TIME, $done = TRUE)- Calculate the current inventory level for a specific asset.farm_inventory_query($asset_id, $time = REQUEST_TIME, $done = TRUE)- Helper function for generating a database query for calculating an asset's current inventory.farm_inventory_enabled(FarmAsset $asset)- Check whether or not inventory management is enabled on an asset.farm_inventory_individual(FarmAsset $asset)- Check whether or not an asset is treated as an individual by default.farm_inventory_asset_types()- Returns a list of asset types that have inventory enabled.farm_inventory_set($asset, $inventory, $timestamp = REQUEST_TIME, $log_type = 'farm_observation', $done = TRUE)- Create a log for adjusting asset inventory.
Data model changes
- New "Inventory" field collection (with "Asset" and "Value" sub-fields) on log types: Input, Activity, Harvest, Seeding, Transplanting, Medical, Observation, Sale, Maintenance.
- New database table {farm_inventory_asset_type} for storing inventory settings associated with each asset type. Columns: type, enabled, individual.
Comments
Comment #2
m.stentaComment #3
m.stentaFilled in the "Proposed resolution" section above with my current thinking.
Comment #4
m.stentaI decided to nix the idea for a "reset" field in the inventory field collections. It was a "nice to have" idea, but it adds a level of complexity that isn't justified at this point. We can reassess if we need to in the future.
I added it originally to accomplish two things:
1 is just a nice-to-have - and you can still reset the inventory manually without it, you just need to know what the current level is and add/subtract to balance it out.
2 is theoretically for performance, but it adds complexity to the queries and code which may not justify itself
-Donald Knuth
Ultimately, if performance is an issue, there are better ways to solve this (I've had to think about this a lot in the Ledger module - http://drupal.org/project/ledger). Caching is most likely the best approach.
Comment #5
m.stentaOutlined the "Remaining tasks" section. Left it open-ended because there may be more steps necessary, but I think this summarizes the first steps towards a bare-minimum data architecture, calculation, and simple UI.
Comment #6
m.stentaAdded content to "User interface changes", "API changes", and "Data model changes" above.
Comment #7
m.stentaWe will want to be able to view "Logs with inventory adjustments" on individual asset pages, similar to "Logs with movements", because they will be using a different asset reference field so won't show up automatically.
Comment #8
m.stentaI've pushed a new farm_inventory branch to my farmOS repo fork on Github: https://github.com/mstenta/farmOS/tree/farm_inventory
It does the following:
I crossed those items off the list above, and will continue to update as progress is made...
Comment #9
m.stentaAdded:
Comment #10
m.stentaAnother consideration came up in recent discussions... updating the issue to include the following (and associated tasks/changes):
I will add a new database table for tracking inventory settings for each asset type. One of them will be whether or not inventory tracking is enabled for that asset type. I'll use that instead of the Units field, which is a cleaner approach overall.
Comment #11
m.stentaMade a bunch of progress on this. Updating issue description accordingly...
Comment #12
m.stentaI decided to split the "Inventory Units" piece out to a separate issue, since it is not an immediate requirement.
See #2916551: Farm Inventory Units
Comment #13
m.stentaRecent discussions in #2469109: [META] Discussion: Asset Groups/Hierarchy have changed the requirements a bit. Groups will NOT have inventory enabled. Animals will. See that issue for more details.
Comment #14
m.stentaI think this feature is pretty much done! I'm going to do a little more thinking/testing before merging it in a closing this issue... but we're looking good!
Comment #16
m.stenta