Quantity om drawing based on total number of parts. iLogic

Quantity om drawing based on total number of parts. iLogic

Anonymous
Not applicable
8,356 Views
35 Replies
Message 1 of 36

Quantity om drawing based on total number of parts. iLogic

Anonymous
Not applicable

Hello Autodesk community!

 

does anyone know how to get the total number of a part from a top assembly down to a drawing?

 

I already have  a solution to the question. BUT, i cannot force inventor to count sub-assemblies. any help would be amazing.

 

With kind regards, Mikael Nanke

 

Here is my code:

 

SyntaxEditor Code Snippet

doc = ThisDoc.Document
Dim oAssyDef As AssemblyComponentDefinition = doc.ComponentDefinition
oAssyDef.RepresentationsManager.LevelOfDetailRepresentations("Master").Activate
Dim oBOM As BOM = oAssyDef.BOM

oBOM.PartsOnlyViewEnabled = True

Dim oBOMView As BOMView = oBOM.BOMViews.Item("Parts Only")

Dim oBOMRow As BOMRow

For Each oBOMRow In oBOMView.BOMRows
    'Set a reference to the primary ComponentDefinition of the row
    Dim oCompDef As ComponentDefinition
    oCompDef = oBOMRow.ComponentDefinitions.Item(1)
    
    Dim CompFullDocumentName As String = oCompDef.Document.FullDocumentName
    Dim CompFileNameOnly As String
    Dim index As Integer = CompFullDocumentName.lastindexof("\")
    
    CompFileNameOnly = CompFullDocumentName.substring(index+1)
    'MessageBox.Show(CompFileNameOnly)
    
     Dim Qty As String
     
    Try    
           Qty = oBOMRow.ItemQuantity
    Catch
        MessageBox.Show("Kunne ikke til f�je Part antal til CompFileNameOnly", "Title")
    End Try
    
    iProperties.Value(CompFileNameOnly, "Custom", "PartQty") = Qty
Next

 

0 Likes
Accepted solutions (1)
8,357 Views
35 Replies
Replies (35)
Message 2 of 36

Anonymous
Not applicable

I know this is not an answer to your question and it irritates me when people do this but you should never have the quantity on the part drawing. It’s a drawing to show how to make the part. If you put a quantity of 12 on a part and 12 on the assembly level than its saying you need 144 parts to make that assembly.  

 

Even know I can think of any circumstance you would want to do it I can try to help with the code. I could be wrong but I think you need to refer to the structured for the sub-assembly Qty. and parts only for total Qty. of parts. If you need I can try to write up a code for you in a couple days.

 

I hope this helps.

0 Likes
Message 3 of 36

Anonymous
Not applicable
Accepted solution

Hello there jddickson.

 

thank you for the reply.

The overall problem is how the production function at my work and they need it, so i'm just simply following orders...

 

but i found a solution and would like to share it!

 

This code take the total quantity of a part and put it on the part as a custom parameter, so when i create a drawing, it state how many they need to produce of the given part.

 

 

SyntaxEditor Code Snippet

Sub Main
'Get current document
doc = ThisDoc.Document
Dim oAssyDef As AssemblyComponentDefinition = doc.ComponentDefinition
'Get the BOM object
Dim oBOM As BOM = oAssyDef.BOM
'enable the Parts Only View
oBOM.PartsOnlyViewEnabled = True
'Get the Parts Only view of the BOM
Dim oBOMViewPO As BOMView = oBOM.BOMViews.Item("Parts Only")
'declare variable for each BOM row.
Dim oBOMRowPO As BOMRow

'For each row in the Parts Only BOM, do the following
For Each oBOMRowPO In oBOMViewPO.BOMRows
    'Set a reference to the primary ComponentDefinition of the row
    Dim oCompDef As ComponentDefinition = oBOMRowPO.ComponentDefinitions.Item(1)
    
    'get the full filename associated to the component in the row. ex: c:\temp\part1.ipt
    Dim CompFullDocumentName As String = oCompDef.Document.FullDocumentName
    Dim CompFileNameOnly As String
    'get the location of the last backslash
    Dim index As Integer = CompFullDocumentName.lastindexof("\")
    'get the filename only from the full filename
    CompFileNameOnly = CompFullDocumentName.substring(index+1)
    
    'MessageBox.Show(CompFileNameOnly)
    
    'get the Qty value in the current row
    Dim Qty As String = oBOMRowPO.TotalQuantity
    
    'check to see if the component is a library part, cc part or read only.
    Dim IsLibCCReadonly As Boolean = LibCCReadonlyChecker(CompFullDocumentName)
    
    'if the file is NOT a library part, cc part or read only.
    If IsLibCCReadonly = False Then
        'set following custom iproperty to equal the QTY from the row
        iProperties.Value(CompFileNameOnly, "Custom", "PartQty") = Qty
    End If
Next

'at this time, the qty value for all parts have been copied to the custom property.'next, the following code will cycle through only the subassemblies.

'if the Structured BOM view is enabled then...
If oBOM.StructuredViewEnabled Then
    'If show First Level is set then turn it off. This will set it to All Levels
    If oBOM.StructuredViewFirstLevelOnly Then
        oBOM.StructuredViewFirstLevelOnly = False
    End If
Else
    'enable the Structured BOM view
    oBOM.StructuredViewEnabled = True
    'set the FirstLevelOnly to false therefore make it All Levels
    oBOM.StructuredViewFirstLevelOnly = False
End If

'Get the Structured view of the BOM
Dim oBOMViewStruc As BOMView = oBOM.BOMViews.Item("Structured")
'declare variable for each BOM row.
Dim oBOMRowStruc As BOMRow
'Create a blank array(list). This will be used to store a list of all subassemblies for comparing if the subassembly already exist.
Dim arrSubAssemblyList As New ArrayList

'call a subroutine to cycle through the structured BOM. It will need the collection of rows, the subassembly list, and 1 is the initial parentqty.
Call QueryBOMRowProperties(oBOMViewStruc.BOMRows, arrSubAssemblyList, 1)

End Sub

Private Sub QueryBOMRowProperties(oBOMRows As BOMRowsEnumerator, arrSubAssembly As ArrayList, oParentQty As Integer)

'declare a incrementer variable
Dim i As Long
'for each row in the structured BOM
For i = 1 To oBOMRows.count
    'get the row based on the incrementer
    Dim oBOMRowStruc As BOMRow = oBOMRows.item(i)
    'get the component definition assocated with the row
    Dim oCompDef As ComponentDefinition = oBOMRowStruc.ComponentDefinitions.item(1)
    Dim oQty As Integer
    
    'If the component is an assembly and it's bom structure is Normal then do the following. else do nothing
    If TypeOf oCompDef Is AssemblyComponentDefinition And oCompDef.BOMStructure = BOMStructureEnum.kNormalBOMStructure Then
            'get the full filename associated to the component in the row. ex: c:\temp\subassembly.iam
            Dim CompFullDocumentName As String = oCompDef.Document.FullDocumentName
            Dim CompFileNameOnly As String
            'get the location of the last backslash
            Dim index As Integer = CompFullDocumentName.lastindexof("\")
            'get the filename only from the full filename
            CompFileNameOnly = CompFullDocumentName.substring(index+1)
            'MessageBox.Show(CompFileNameOnly)
            
            'get the qty of the row and multiply by the parent qty.
            oQty = oBOMRowStruc.ItemQuantity * oParentQty
            
            'create a variable that will be used to get the qty of the subassembly if it was used elsewhere
            Dim additionalQty As Integer = 0
            'if the subassembly list is not empty then...
            If arrSubAssembly.Count <> 0 Then
                'create a counter. this will be used to determine which item in the subassembly array (list) when it finds a match.
                'this counter will be used to edit that item with the new qty.
                Dim counter As Integer = 0
                'for each item in the subassembly array (list) starting at 0 (first item) to last item
                For j As Integer = 0 To arrSubAssembly.Count-1
                    'get the location of the colon
                    Dim commaindex As Integer = arrSubAssembly(j).indexof(":")
                    'get just the file name
                    Dim CompName As String = arrSubAssembly(j).substring(0,commaindex)
                    
                    'if the file name of the current row matches the current item in the subassembly array (list) then...
                    If CompName = CompFileNameOnly Then
                        'set the additional qty to the qty found in the subassembly array (list)
                        additionalQty = arrSubAssembly(j).substring(commaindex+1)
                        'set the counter equal to the item in the subassembly array (list)
                        counter = j
                        'since a match is found, we need to exit the for loop so that counter no longer increments.
                        'so Set j To the number of items in the subassembly array. this will exit out the for loop.
                        j = arrSubAssembly.Count
                    Else
                        'increase the counter
                        counter += 1
                    End If
                Next
                
                'if additional qty was not changed then there was no match. It will be a new item in the subassembly array (list)
                If additionalQty = 0 Then
                    'add the subassambly to the subassembly array (list)
                    arrSubAssembly.add(CompFileNameOnly & ":" & oQty)
                Else
                    'if it did find a match, then update the qty for that item in the subassembly array (list)
                    arrSubAssembly(counter) = CompFileNameOnly & ":" & oQty + additionalQty
                End If
            Else
                'add the first subassembly to the list. It will add the filename and the qty separated by a colon. ex. subassembly.iam:2
                arrSubAssembly.add(CompFileNameOnly & ":" & oQty)
            End If
            
            'check to see if the component is a library part, cc part or read only.
            Dim IsLibCCReadonly As Boolean = LibCCReadonlyChecker(CompFullDocumentName)
            
            'if the file is NOT a library part, cc part or read only.
            If IsLibCCReadonly = False Then
                'set following custom iproperty to equal the QTY from the row plus the additional qty value
                iProperties.Value(CompFileNameOnly, "Custom", "PartQty") = oQty + additionalQty
            
                'Recursively iterate child rows if present.
                If Not oBOMRowStruc.ChildRows Is Nothing Then
                    'recall the subroutine, push the childrows of the sub, sub assembly array (list), and the qty of the subassembly
                    Call QueryBOMRowProperties(oBOMRowStruc.ChildRows, arrSubAssembly, oQty)
                End If
            End If
        End If
    Next
End Sub

Private Function LibCCReadonlyChecker(filename As String) As Boolean
' Get the active project
Dim oProject As DesignProject = ThisApplication.DesignProjectManager.ActiveDesignProject
' Get all the library paths
Dim oLibraryPaths As ProjectPaths = oProject.LibraryPaths
Dim oLibraryPath As ProjectPath

'for each library path in the list of all library paths
For Each oLibraryPath In oLibraryPaths
    'get the library path
    Dim oLibs As String = oLibraryPath.Path
    'if the file is in a library path then Return True
    If filename.Contains(oLibs) = True Then
        Return True
    End If
Next

'if the file is in the CC location then Return True
If filename.Contains(oProject.ContentCenterPath) = True Then
    Return True
End If

'get read only status
Dim File_Attr As Long = System.IO.File.GetAttributes(filename)
'if the file is readonly or readonly and archieve then Return True
If File_Attr = 1 Or File_Attr = 33 Then
    Return True
End If

'return False if it's not a library, CC or a Readonly part.
Return False

End Function

 

Message 4 of 36

timothy_berg
Advocate
Advocate

This works for me thanks for posting

0 Likes
Message 5 of 36

timothy_berg
Advocate
Advocate

The code does work for my application, however I'm trying to convert it from Qty to Item Qty in the master BOM. I have structural members in this assembly and would like to have a qty of cut pieces instead of a linear length. Please let me know what needs to change.

0 Likes
Message 6 of 36

b.mccarthy
Collaborator
Collaborator

Thank you for this, however, the routine has decided not to play nicely....

 

I made one change to the code from:

   Dim Qty As String = oBOMRowPO.TotalQuantity

  to:
   Dim Qty As String = oBOMRowPO.ItemQuantity

 

The routine was running perfectly for about an hour after this change, and then started throwing this error:

Error Message:

   Error in rule: AssyCount, in document: CX-A-001968.iam
   The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))

 

More Info:

System.ArgumentException: The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))
   at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
   at Inventor.BOMViews.get_Item(Object Index)
   at LmiRuleScript.Main()
   at Autodesk.iLogic.Exec.AppDomExec.ExecRuleInAssembly(Assembly assem)
   at iLogic.RuleEvalContainer.ExecRuleEval(String execRule)

 

Any idea what went awry?

0 Likes
Message 7 of 36

P_Korgaonkar
Advocate
Advocate

Dear Mikael

 

This is a great piece of work

I had been trying to find this solution for years, and stumble upon this thread by accident.

 

This will save me a lot of hours.

 

May God bless you.

Thank you once again.

 

Regards

Parag

Message 8 of 36

GosponZ
Collaborator
Collaborator

Good rule thanks for sharing. I do have question. Can this one be updated say i do have 5 units. Can be added code to multiply total qty with unit number, so each part has total qty for production. Those Library parts, can they be count. If someone see this please help to solve long time problem. Thank you

0 Likes
Message 9 of 36

P_Korgaonkar
Advocate
Advocate

You need to run the rule every time you change the assembly.

So run the rule just before you start detailing the drawings and you will have latest total quantity.

I believe it updates the library parts too. But be carful, you need to run the rule again if you switch the project, or you will end up with wrong quantity!

 

Regards

Message 10 of 36

GosponZ
Collaborator
Collaborator

Thanks for answering so quick. It doesn't update library parts. This will work for me if i can multiply PartQty with number of my units we build. 

iProperties.Value("Custom", "TTL") = iProperties.Value("Custom", "PartQty") * iProperties.Value("Custom", "Unit_Qty")

Something like this line. It is working just on part but would be perfect if will work just after your code to multyply so i can see total qty say panels in one unit is qty 2 but for 5 units is 10

Message 11 of 36

Anonymous
Not applicable

Hello there!
you are correct, as for Inventor 2021 and I think 2020, they made some changes in how the codes work and what you are "allowed" to do.

This means this code cannot change libary parts anymore. 🙂

0 Likes
Message 12 of 36

Anonymous
Not applicable

What I normaly do to count a specifik ammount. Is to create a new assembly with the given project number.

place the 5x subassemblies you need in the assemly, then use the counting code, this will give the drawing of the part the correct number, if you want to "save" the ammount of items you have used for a project, it's best you save/copy design the files into a new folder where they can store the information for next time.

0 Likes
Message 13 of 36

GosponZ
Collaborator
Collaborator

Thank you. That is interesting approach  to total qty. But still I'm interested if is possible to multiply those 2 iprops. and to give you total without makes extra asssembly

0 Likes
Message 14 of 36

GosponZ
Collaborator
Collaborator

Ok i figure out. I made parameter Unit_Qty. and replaced in your code

 'set following custom iproperty to equal the QTY from the row
		

        iProperties.Value(CompFileNameOnly, "Custom", "TTL") = Qty * Parameter("Unit_Qty")

Do not need make another assembly 5 times.  Make for m with that parameter and rule. Thant is it. Works for me perfect.

0 Likes
Message 15 of 36

P_Korgaonkar
Advocate
Advocate

Hello,

This rule was working great so far.

Today I am getting an attached error.

Can anyone help me understand what's going on?

 

Thanks in advance.

Regards

Parag

0 Likes
Message 16 of 36

A.Acheson
Mentor
Mentor

Can you place a message box at various points along the code especially at entrance to sub routine to check how far along it gets and where it may stop. 

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
0 Likes
Message 17 of 36

P_Korgaonkar
Advocate
Advocate

Thank you for your suggestion.

I dont know how to do it, I have just copied this code and used it.

Can you help?

 

Update this code with message boxes, and share it here if possible. I can test and give the result ASAP..

 

Thank you.

 

0 Likes
Message 18 of 36

A.Acheson
Mentor
Mentor

Can you check if the rule was run in the master level of detail? 

 

 

Here is a snippet to paste in where indicate on the picture below. You can use this to  verify the rule is outputting qty values.

Logger.Info(Qty, "Progress Check")

 

 

AAcheson_0-1631540368532.png

 

You can place a message box  in the rule to indicate how far the rule gets. If you get an error before you reach the message box the error has then occurred before the message box. 

MessageBox.Show("Message", "Title")

 

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
0 Likes
Message 19 of 36

P_Korgaonkar
Advocate
Advocate

Thank you A.Acheson

 

I tried as you suggested.

I have checked all assemblies are in Master representation.

Then I have added the snippet and message box where you suggested.

 

I got the Message box and had click OK 140 times first time I ran the rule, but this number kept changing every time I ran the rule again.

Rule ran and did not get an error at the end, but assembly quantity did not update.

All part quantities update to the correct number, but some sub assemblies don't.

If I delete custom property from the sub assembly and run the rule again, the property is not created again, meaning the rule does not work on sub assembly.

The Log shows INFO number every time I click OK in the message box..

 

Just to let you know this rule was working on the same Assembly few weeks back, the earlier models from the backup work, but after changes done in last couple of weeks it has stopped working. I am not able to pin point what changes made this not to work.

 

If you an advise further steps it will be greatly appreciated.

 

 

0 Likes
Message 20 of 36

A.Acheson
Mentor
Mentor

Hmm interesting one. Yes a message box can be a dangerous tool when debugging. I would use it cautiously inside a for loop otherwise you will become weary of clicking. You can employ a trusty weight on the enter key to save the clicking😂 if it happens. 


Any chance of attaching a small data set of the files not working using pack and go in a zipped folder. You can delete out the contents of the files just as long as the files stay there to show there structure and if read only etc, library file etc. Looking at the above messages there was an error message that wasn’t fixed I believe. 

Is the error message occurring each time? 

 

You can also wrap the iProperty statement in a try catch statement and place a log message there and if the iProperty cannot be written to the file it will error out and write the log message with the filename it occurred on. 

 

 Try
 iProperties.Value(CompFileNameOnly, "Custom", "PartQty") = Qty  Catch
Logger.Info(CompFileNameOnly, "Document Failed")
End Try

 

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
0 Likes