Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to modify a completed build #977

Closed
wolffam opened this issue Sep 14, 2020 · 13 comments · Fixed by #1063
Closed

Add ability to modify a completed build #977

wolffam opened this issue Sep 14, 2020 · 13 comments · Fixed by #1063

Comments

@wolffam
Copy link
Contributor

wolffam commented Sep 14, 2020

Hi there! I am hoping to use Inventree for keeping an inventory of hardware components but there is a feature that I need which is not currently implemented.

An example of the use case:

  • 2 components (Part A and Part B) make an assembly (Assembly A)
  • A "build" is performed given the BOM items above and serial numbers 1 and 2 are used for Part A and Part B respectively
  • The build is completed and that assembly becomes a stock item (subsequently removing stock for parts A and B)
  • Some time passes and the Part A (serial number 1) installed in that completed build needs to be replaced by Part A (serial number 11)
  • Part A (serial 1) would be unallocated and the status can be changed to reflect its new state. Part A (serial 11) would need to be allocated to the build and the build would need to be re-completed again.

From messing around the code base a bit, it seems that every time the build is moved from "Pending" to "Completed", it makes a new build output. I would imagine some business logic needs to be added to handle this scenario.

Is this a use-case Inventree purposely does not want to allow or does it just need to be coded up? I'm new to django but wouldn't mind giving this a try if I'm aware of the common pitfalls when adding a feature like this.

@SchrodingersGat
Copy link
Member

This is a great idea, and I have been thinking about how to implement something like this for quite some time.

Is this a use-case Inventree purposely does not want to allow or does it just need to be coded up?

It "simply" needs to be implemented!

Background Reading: - #918

For this to work, the first step is to implement the concept of "installing" a StockItem inside another StockItem (e.g. track a single serialized item inside another).

Currently this does not work - a "build" captures much more generic information about stock items that go into a particular build. But it does not currently record which particular unique items were assigned to which particular build outputs.

  • 20 screws from this packet were consumed to make this build

@wolffam
Copy link
Contributor Author

wolffam commented Sep 21, 2020

Starting to try and make some progress on this for single output builds. Here are some initial screenshots for how it would look to move a build into "MODIFYING" state.
Screen Shot 2020-09-20 at 11 59 53 PM

Screen Shot 2020-09-21 at 12 00 03 AM

The next step is figuring out the right way to handle the actual uninstall of current items and install of new items. Can it follow the unallocation and allocation models? Maybe uninstalling is similar to unallocating but it also allows the user easy access to change the status of the item? Thoughts here would be appreciated. For now, I'm just going to try and plow ahead.

@SchrodingersGat
Copy link
Member

I can see the required UI elements to facilitate "uninstalling" parts from a build (especially when the build has multiple outputs) becoming quite complex.

But, probably necessarily complex (I don't see a way of avoiding it really).

At a "minimum" I think there needs to be ways for the user to:

  1. Specify which trackable sub-parts are installed in which output (for multi-output builds)
  2. A way to "uninstall" an installed sub-part from a part (without necessarily modifying the build)
  3. A way to "revert" or "modify" a completed build. Perhaps this looks the same as uninstalling the installed sub-parts and placing them back into stock.

I think that "modifying" a build is much the same as unallocating parts, with the difference being that these need to be "uninstalled" from the output parts.

@wolffam
Copy link
Contributor Author

wolffam commented Sep 25, 2020

Hi @SchrodingersGat ,
I added some screenshots of where I currently am at on this project in #993.
I think I currently address Points 2 and 3 but I would like your opinion on what I have so far. My workflow doesn't require ordering/selling so if that requires integration, let me know and I can figure out how those operate. And I agree that the UI will get complicated for builds with more than 1 output (which is why I am not diving into that at the moment)

@SchrodingersGat
Copy link
Member

I have been thinking about this over the weekend, and I think I have a potential solution which is a bit more generic, particularly in terms of allowing multiple build outputs for a build. This is a feature which I know would be of great use to my workplace, where we make parts in "batches" and might have 20-50 unique outputs in a single build.

The following thoughts relate to this PR and also to #993 and #991

The current way that a build is intended to work is that after the build is complete, a new stock item is generated, and any allocated items are then removed from stock and installed in the new stockitem. (Note: currently this is not actually the case, the allocated items are instead allocated to the build, not the generated output stockitem).

A new approach would be to create the new stock items immediately (when the build is created). The allocation process allocates sub-items to the new stockitems, and not the build object.

  • Add a new stock item status flag BUILDING which shows that the new stock item does not exist yet
  • Serial numbers are allocated to the new stock item (which then has the added benefit of reserving the serial numbers)
  • Once an output stockitem is fully allocated, it can be marked as "COMPLETE"
  • In this manner, output items can be individually completed, which addresses Partial build completion #572

Allocating Stock

In terms of how stock gets allocated:

Non-Trackable Parts

Non-trackable parts can be allocated semi-automatically in much the same way they are currently. It does not particularly matter which parts are installed into a given output.

Trackable Parts

Sub-parts marked as trackable must be manually and individually installed into the generated stock items. This forces the user to pick which serialized stock items are installed into which output stock item.

User Interface

The UI would not actually have to change that much with this approach. Instead of having a single table for allocation of stock to the build, there would be a copy of this table for each "output" of the build. Each table would have a progress bar indicating how much of the allocation has been completed.

Each "output" would be minimized when completed, and can be expanded to see which stock have been allocated.

Something like this

image

I'm not yet 100% across your changes, but it did get me thinking how a generic solution could be implemented. Let me know if you have any thoughts on this. It would be a pretty big change, especially having to consider how to migrate from the existing way that builds are managed...

@wolffam
Copy link
Contributor Author

wolffam commented Oct 4, 2020

@SchrodingersGat , I think that approach makes sense for the initial builds/installing. I really like the "uninstall" feature that you added onto the build items.
A couple questions I still have:

  1. Do you have a vision/preference for how add the ability to install new stock items into a previously completed build output? Do you want the status to change at all or would a lightweight button (similar to the uninstall button) suffice?
  2. What parts of this process are you actively working on and what parts would you like help with? Before I can use Inventree in my production environment, I will require the uninstall/install feature so I am keen on helping to get that up and running.

-Alex

@SchrodingersGat
Copy link
Member

Do you have a vision/preference for how add the ability to install new stock items into a previously completed build output? Do you want the status to change at all or would a lightweight button (similar to the uninstall button) suffice?

I think that the "Build" process controls what happens during a build, and then generates one or more output stock items (which will have other stock items installed in them). Once the Build process is finished, any "uninstallation" of installed stock items is not really part of the build process, as the build order has been completed.

However, there should be an easy way to either uninstall items from a parent item (which has now been implemented) and in a similar fashion, a simple way to install more items.

Here's one way I can imagine that happening:

In the "Installed Items" tab for a given stock item, in addition to showing rows for each installed stock item, we can add rows for each "part" in the BOM. This way, we can see if any BOM items have not been installed (or have been installed and then uninstalled) and thus how "complete" this part is.

  • These extra rows would only be added for installed items which are "trackable" (i.e. you might not want to track every 0402 capacitor you load onto a board)
  • Using BOM data lets you reduce the dataset of available stock items
  • Installing a new stock item would be as "simple" as clicking on a button next to the part row
  • Each "row' could have a progress bar showing how much of the required BOM items have been installed
  • The "uninstall" process would make use of the same table

Here's a very rough mockup:

image

What parts of this process are you actively working on and what parts would you like help with? Before I can use Inventree in my production environment, I will require the uninstall/install feature so I am keen on helping to get that up and running.

I am currently working on this manual install / uninstall table, to make the changes as roughly detailed above. I'll @ you in the PR so you can test it out.

The other big change is to the Build process, which will generate stock items at the start of the build process, but mark them as "building".

That will require the following changes:

  • Add a boolean field to the StockItem model called "building" (default=False) to denote that a particular stock item is being built
  • Add functionality to the in_stock method so that any stock item which is "building" is not considered to be in stock
  • Add functionality to the "Add New Build Order" step which creates stock items (this step will enforce setting build quantity and serial numbers)
  • Build Order quantity field cannot be changed after generation
  • To "add" new outputs to a build order, say you wanted 5 but now you want 6, this is a separate process of creating a new stockitem and adding this as an output for the build
  • You can "remove" build outputs in a similar way (this will delete the stock item and also remove any allocations to that stock item)
  • Update the "BuildItem" model which currently only points to a build, to also point to a StockItem (this is so when the build item is completed, the allocated items are installed in the output
  • Add UI elements to mark a particular build output as "completed" (which sets the "building" field to false, and performs the tasks of installing the stock items into the build output
  • Add UI elements to mark all build outputs as complete
  • LOTS of unit testing!

If there are any steps in that list that you want to tackle (and I guess the development order is roughly top to bottom) then let me know. I'm happy to provide pointers if you need.

This feature is the next-most-useful feature for me too, so I'm keen to get it working correctly. Implementing this solution will close out a lot of outstanding issues too, so I'm very happy about that :)

@wolffam
Copy link
Contributor Author

wolffam commented Oct 4, 2020

Sounds great! I can try and make some progress on that list of todos tomorrow. Is there a branch I should work from or is master recent enough?

@wolffam
Copy link
Contributor Author

wolffam commented Oct 4, 2020

I have a specific question you could probably help me with:
If I want to run a chunk of code right after valid form data has been successfully submitted, is there a function that I can override that would give me that hook? It seems like form_valid should do that, but I am not seeing that behavior.

@SchrodingersGat
Copy link
Member

There's a lot of places where this could be achieved, some "better" than others.

I'm still learning a lot about the "django way" to do things and so you'll no doubt find many functions in the InvenTree code base that perform the same task in wildly different ways.

Some context here would help, I think.

  • What is the action you are trying to perform?
  • Do you want the action to run after the form is validated, or after the model is saved to the database? Or at some other point?

You can handle this either in the form class, or in the view class which handles the form. Depending on whether the actions are to do with form validation, or back-end database actions, will somewhat determine the "best" answer here.

But walk me through what exactly you're trying to do and I'm sure we can work something out.

@wolffam
Copy link
Contributor Author

wolffam commented Oct 5, 2020

This would be relevant for creating the stock items of the build outputs at the time of build creation and specifically once the user has successfully submitted a valid "Create Build Form." I think I would want it to run after the form is validated and before the model is saved (since I want to add information to the model). Any suggestions?

@SchrodingersGat
Copy link
Member

Check out the AjaxCreateView class which offers pre_save and post_save hooks.

I think you would actually want to perform this step after saving the Build object, as you need to point the generated stockitem objects to the build.

e.g.

# After build item has been saved
build = get_object()

# Create some stock items
for i in range(build.quantity):
    StockItem.objects.create(
        part=build.part,
        quantity=1,
        is_building=True
    )

# This will automatically link the new stockitem objects to the build object using the 'build_outputs' lookup

outputs = build.build_outputs.all()

@wolffam
Copy link
Contributor Author

wolffam commented Oct 5, 2020

Didn't have as much time today as I hoped but I started #1021 to log the changes I've made so far. Trying to keep each commit isolated enough to reference the line items you had listed above.
I ran into a problem getting get_object to work within the post_save hook. I worked around that for now by passing the build object into the function but I'm most likely missing something

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants