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

Correct way to obtain substitute part list and BOM depth "level" #176

Open
tehkillerbee opened this issue Mar 20, 2023 · 1 comment
Open

Comments

@tehkillerbee
Copy link

tehkillerbee commented Mar 20, 2023

Hello,

I have been using the InvenTree API to generate BOMs in a custom XLSX format. It seems the InvenTree web does not allow me to export specific fields from the BOM to XLSX and it seems easier to use the API directly. Then I can also format the text (color etc.)

These are the steps I have used so far:

  1. Iterate over all Parts on the server.
  2. For each Part, get the BOM associated to it (part.getBomItems()). Select Parts that has a valid BOM assigned to it.
    api = InvenTreeAPI(SERVER_ADDRESS, username=MY_USERNAME, password=MY_PASSWORD)
    parts = Part.list(api)

    row = 0
    for part in parts:
        try:
            bom_list = part.getBomItems()
        except:
            continue

        # Skip items with no BOM
        if len(bom_list) == 0:
            continue
  1. Sort the BOM list is sorted in "assembly" parts and "non-assembly" parts. This allows nicer sorting so assemblies are always processed last when printed in the XLSX sheet. This might not be the smartest way to sort the list, but it works
    # Sort BOM part types (i.e. individual parts, followed by sub-assemblies)
    # Note: Looking up parts from BomItems is kinda slow...But it works
    bom_list_main = []
    bom_list_subs = []
    bom_list_sorted = []
    for bom_item in bom_list:
        try:
            sub_part = Part(api, pk=bom_item.sub_part)
            if sub_part.assembly:
                bom_list_subs.append(bom_item)
            else:
                bom_list_main.append(bom_item)
        except:
            continue
    bom_list_sorted.extend(bom_list_main)
    bom_list_sorted.extend(bom_list_subs)
  1. Iterate over all BOM Parts. Calculate required quantity. Print the relevant fields to the XLSX worksheet.
    for bom_item in bom_list_sorted:
        try:
            # Lookup selected BOM part
            part = Part(api, pk=bom_item.sub_part)

            # Calculate build quantity, assuming current stock (round to nearest)
            can_build = bom_item.available_stock / (bom_item.quantity * bom_multiplier) if bom_item.quantity else 0

            if part.assembly:
            # Handle nested BOMs, i.e. when BOM part is an assembly:
            # Sort nested BOM items again
            # Handle nested BOM and print fields to XLSX
            ...
            else:
            # Handle individual BOM items:
            ...
  1. Some BOMs contain nested BOMs so these are handled by repeating step 3-5 recursively.

The above steps handle all situations, except substitute parts, so I am now trying to handle that.
For each bom_item , i get the list of substitutes (bom_item.substitutes). This list does not contain a list of Parts as expected, but a list with a dict for each substitute part. I convert this to a Part by the following dict look-up:

part = Part(api, pk=substitute['part_detail']['pk'])
  1. I was expecting to be able to access substitute.pk etc. directly. Is there something I am missing?
  2. When I handle nested BOMs, I keep track of the BOM level/depth by hand to allow easier sorting of the components. Is there a different way to get hold of the BOM "depth" index directly using the API? Otherwise, I have to keep track of the BOM "depth" each time i detect sub_part.assembly
  3. Is there a way to obtain a sorted BOM list from the API? Eg. if I want to sort by Assemblies or items with a stock quantity of 0?

On an unrelated note. I was wondering if these scripts I have been working on can be useful in any way - perhaps as an "example" of how to use the API. This API has been most useful, so it would be nice to give back to the project somehow. :)

@SchrodingersGat
Copy link
Member

SchrodingersGat commented Mar 21, 2023

I was expecting to be able to access substitute.pk etc. directly. Is there something I am missing?

This is expected. The pk value here is for the BomItemSubstitute instance, not the part:

https://github.com/inventree/InvenTree/blob/4d8311682c2b646700eb0a87ecffda6e4f38467c/InvenTree/part/models.py#L3818

Is there a different way to get hold of the BOM "depth" index directly using the API?

No, 'depth' is not stored or calculated for bills of materials

Is there a way to obtain a sorted BOM list from the API? Eg. if I want to sort by Assemblies or items with a stock quantity of 0?

You can see the available 'filtering' options here:

https://github.com/inventree/InvenTree/blob/4d8311682c2b646700eb0a87ecffda6e4f38467c/InvenTree/part/api.py#L1598

The 'ordering' fields are somewhat limited:

https://github.com/inventree/InvenTree/blob/4d8311682c2b646700eb0a87ecffda6e4f38467c/InvenTree/part/api.py#L1810

On an unrelated note. I was wondering if these scripts I have been working on can be useful in any way - perhaps as an "example" of how to use the API.

Certainly you could add something like this to our "examples" page:

https://docs.inventree.org/en/latest/api/python/examples/

The docs are managed on github too - you can raise a PR here - https://github.com/inventree/inventree-docs/pulls

This API has been most useful, so it would be nice to give back to the project somehow. :)

Much appreciated! InvenTree is very much community driven, so any support would be appreciated :)

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

No branches or pull requests

2 participants