Community
Inventor Programming - iLogic, Macros, AddIns & Apprentice
Inventor iLogic, Macros, AddIns & Apprentice Forum. Share your knowledge, ask questions, and explore popular Inventor topics related to programming, creating add-ins, macros, working with the API or creating iLogic tools.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Qty in bom

38 REPLIES 38
SOLVED
Reply
Message 1 of 39
GosponZ
8120 Views, 38 Replies

Qty in bom

In Bill of material i have custom PartQty column and is beside QTY column. I need  all informations from QTY column to PartQty column to copy. Possible with iLogic? I'm selecting now manualy copy and paste but it would be nice to have automatic. Could you guys help with please.

Thank you

Capture.JPG

38 REPLIES 38
Message 21 of 39
danvang
in reply to: GosponZ

If you search the discussion group there are some code that some people are using to get the library paths and the file attribute (read only). The checked out status may be tricker. Below are some code to get the library paths, content center path and the file attribute status. If you want the check out status, you may need to check out the vault customization forum. You will need to do these checks before the "iProperties.Value(CompFileNameOnly, "Custom", "PartQty") = Qty" line of code. Hope this helps point you in the right direction.

 

-------------

'Get the library paths.

Dim oProjectMgr As DesignProjectManager = ThisApplication.DesignProjectManager
' Get the active project
Dim oProject As DesignProject = oProjectMgr.ActiveDesignProject
' Get the library paths
Dim oLibraryPaths As ProjectPaths = oProject.LibraryPaths
Dim oLibraryPath As ProjectPath

 

For Each oLibraryPath In oLibraryPaths
    Dim oLibs As String = oLibraryPath.Path
    messagebox.show(oLibs)
Next

 

'get the content center path

messagebox.show(oProject.ContentCenterPath)

 

---------------------

'get read only status
 Dim File_Attr As Long = System.IO.File.GetAttributes("c:\temp\part1.ipt")

 

If File_Attr = 1 Or File_Attr = 33 Then
     messagebox.show("read only")

else

     messagebox.show("NOT read only")
End If

 

** If my reply resolves this issue, please choose "Accept as Solution" **
Dan Vang
Message 22 of 39
danvang
in reply to: eljoseppo

Eljoseppo,

 

I found the issue. I used a "For each" when I am incrementing the Counter variable. Therefore counter will still increment if it found a match previously and then makes the counter out of range when it's editing the list. Should have used a regular "For" and then stop it when it finds a match. Below is the updated code. See how this works for you.

 

 


Sub Main
doc = ThisDoc.Document
Dim oAssyDef As AssemblyComponentDefinition = doc.ComponentDefinition
Dim oBOM As BOM = oAssyDef.BOM

oBOM.PartsOnlyViewEnabled = True

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

Dim oBOMRowPO As BOMRow

For Each oBOMRowPO In oBOMViewPO.BOMRows
    'Set a reference to the primary ComponentDefinition of the row
    Dim oCompDef As ComponentDefinition
    oCompDef = oBOMRowPO.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
    Qty = oBOMRowPO.TotalQuantity
    
    iProperties.Value(CompFileNameOnly, "Custom", "cQty") = Qty
Next

If oBOM.StructuredViewEnabled Then
    If oBOM.StructuredViewFirstLevelOnly Then
        oBOM.StructuredViewFirstLevelOnly = False
    End If
Else
    oBOM.StructuredViewEnabled = True
    oBOM.StructuredViewFirstLevelOnly = False
End If

Dim oBOMViewStruc As BOMView = oBOM.BOMViews.Item("Structured")
Dim oBOMRowStruc As BOMRow
Dim arrSubAssemblyList As New ArrayList

Call QueryBOMRowProperties(oBOMViewStruc.BOMRows, arrSubAssemblyList, 1)

End Sub

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

Dim i As Long

For i = 1 To oBOMRows.count

    Dim oBOMRowStruc As BOMRow = oBOMRows.item(i)
    
    Dim oCompDef As ComponentDefinition = oBOMRowStruc.ComponentDefinitions.item(1)
    Dim oQty As Integer
        
    If TypeOf oCompDef Is AssemblyComponentDefinition And oCompDef.BOMStructure = BOMStructureEnum.kNormalBOMStructure Then
            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)
            
            oQty = oBOMRowStruc.ItemQuantity * oParentQty
            
            Dim additionalQty As Integer = 0
            
            If arrSubAssembly.Count <> 0 Then
            
                Dim counter As Integer = 0
                For j As Integer = 0 To arrSubAssembly.Count-1
                    Dim commaindex As Integer = arrSubAssembly(j).indexof(":")
                    Dim CompName As String = arrSubAssembly(j).substring(0,commaindex)

                    If CompName = CompFileNameOnly Then
                        additionalQty = arrSubAssembly(j).substring(commaindex+1)
                        counter = j
                        j = arrSubAssembly.Count
                    Else
                        counter += 1
                    End If
                Next
                
                If additionalQty = 0 Then
                    arrSubAssembly.add(CompFileNameOnly & ":" & oQty)
                Else
                    'edit
                    arrSubAssembly(counter) = CompFileNameOnly & ":" & oQty + additionalQty
                End If
            Else
                arrSubAssembly.add(CompFileNameOnly & ":" & oQty)
            End If
            
            For Each item in arrSubAssembly
                datalog &= item & vbCr
            Next
            
            iProperties.Value(CompFileNameOnly, "Custom", "cQty") = oQty + additionalQty
            
            'Recursively iterate child rows if present.
            If Not oBOMRowStruc.ChildRows Is Nothing Then
                Call QueryBOMRowProperties(oBOMRowStruc.ChildRows, arrSubAssembly, oQty)
            End If
        End If
    Next
End Sub

** If my reply resolves this issue, please choose "Accept as Solution" **
Dan Vang
Message 23 of 39
GosponZ
in reply to: danvang

I'm trying but with no success. Thanks for your help.

Message 24 of 39
danvang
in reply to: GosponZ

Upload what you have and I can take a look later tonight.

** If my reply resolves this issue, please choose "Accept as Solution" **
Dan Vang
Message 25 of 39
GosponZ
in reply to: danvang

I'm apreciate your help. Basicly there is nothing to upload. Your code is working perfect what i need, but i would like to upgrade code even more. How to recognise Library parts (Vaut) and not count them into PartQty. That will be it. I tried what you suggest but without success.

Thank you

Sub Main

doc = ThisDoc.Document

Dim oAssyDef As AssemblyComponentDefinition = doc.ComponentDefinition

Dim oBOM As BOM = oAssyDef.BOM

 

oBOM.PartsOnlyViewEnabled = True

 

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

 

Dim oBOMRowPO As BOMRow

 

For Each oBOMRowPO In oBOMViewPO.BOMRows

    'Set a reference to the primary ComponentDefinition of the row

    Dim oCompDef As ComponentDefinition

    oCompDef = oBOMRowPO.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

    Qty = oBOMRowPO.TotalQuantity

   

    iProperties.Value(CompFileNameOnly, "Custom", "PartQty") = Qty

Next

 

If oBOM.StructuredViewEnabled Then

    If oBOM.StructuredViewFirstLevelOnly Then

        oBOM.StructuredViewFirstLevelOnly = False

    End If

Else

    oBOM.StructuredViewEnabled = True

    oBOM.StructuredViewFirstLevelOnly = False

End If

 

Dim oBOMViewStruc As BOMView = oBOM.BOMViews.Item("Structured")

Dim oBOMRowStruc As BOMRow

Dim arrSubAssemblyList As New ArrayList

 

Call QueryBOMRowProperties(oBOMViewStruc.BOMRows, arrSubAssemblyList, 1)

 

End Sub

 

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

 

Dim i As Long

 

For i = 1 To oBOMRows.count

 

    Dim oBOMRowStruc As BOMRow = oBOMRows.item(i)

   

    Dim oCompDef As ComponentDefinition = oBOMRowStruc.ComponentDefinitions.item(1)

    Dim oQty As Integer

       

    If TypeOf oCompDef Is AssemblyComponentDefinition And oCompDef.BOMStructure = BOMStructureEnum.kNormalBOMStructure Then

            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)

           

            oQty = oBOMRowStruc.ItemQuantity * oParentQty

           

            Dim additionalQty As Integer

           

            If arrSubAssembly.Count <> 0 Then

                Dim counter As Integer

                For Each CompData As String In arrSubAssembly

                    Dim commaindex As Integer = CompData.indexof(",")

                    Dim CompName As String = CompData.substring(0,commaindex)

                    If CompName = CompFileNameOnly Then

                        additionalQty = CompData.substring(commaindex+1)

                    Else

                        counter += 1

                    End If

                Next

               

                If additionalQty = 0 Then

                    arrSubAssembly.add(CompFileNameOnly & "," & oQty)

                Else

                    arrSubAssembly(counter) = CompFileNameOnly & "," & oQty + additionalQty

                End If

            Else

                arrSubAssembly.add(CompFileNameOnly & "," & oQty)

            End If

           

            iProperties.Value(CompFileNameOnly, "Custom", "PartQty") = oQty + additionalQty

           

            'Recursively iterate child rows if present.

            If Not oBOMRowStruc.ChildRows Is Nothing Then

                Call QueryBOMRowProperties(oBOMRowStruc.ChildRows, arrSubAssembly, oQty)

            End If

        End If

    Next

End Sub

 

 

Message 26 of 39
danvang
in reply to: danvang

The code you uploaded didn't have any of the code I mentioned about checking for library, content center or read only parts. But here is the final code i'm thinking. If you want the vault checked out status, you will need to check the vault customization forum.

 

With the code that I mentioned earlier, i simply created a function to check if the file is a library, content center or a readonly file. If it's NOT any of those then allow the writing of the custom iproperty. I applied it to both parts and subassemblies. I also placed in comments so you can understand what's going on.

 

 


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", "cQty") = 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", "cQty") = 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

** If my reply resolves this issue, please choose "Accept as Solution" **
Dan Vang
Message 27 of 39
GosponZ
in reply to: danvang

Wow that was so fast and such big code. I really apreciate.But here is one maybe little problem. Rule run no error. Perfect. When i checked Bom it shows as is on this att. picure. In first row i inserted 3 parts and second raw 5 LIBRARY parts. Part Qty for Library parts is PERFECT.I do not need better 5 qty and nothing in PartQty, but first row shows 3 in qty and 1 in PartQty. Both should be 3. What is happening?

 

Thank you so much

Message 28 of 39
danvang
in reply to: GosponZ

I created a sample assembly with 3 normal parts and 5 library parts. It's working fine here. Make sure you edit the last code to use PartQty instead of cQty.
** If my reply resolves this issue, please choose "Accept as Solution" **
Dan Vang
Message 29 of 39
Jefkee
in reply to: danvang

Hmm...

 

And i get this error. Can you copy the code u used into the code dialog box? Maybe this would help.

 

Rule Compile Errors in Test BOM aantallen 2, in Test BOM aantal_Hoofdassembly.iam

Error on Line 158 : End of statement expected.
Error on Line 160 : 'oProject' is not declared. It may be inaccessible due to its protection level.
Error on Line 174 : 'oProject' is not declared. It may be inaccessible due to its protection level.

 

Inventor 2013
Message 30 of 39

works perfect vladimir, exactly what i was looking for.

Message 31 of 39
Nsteel
in reply to: Jefkee

I had  the same errors, then I changed line 159 to:

 

Dim oProject As Deisgn Project

oProject = ThisApplicatio.DesignProjectManager.ActiveDesignProject

 

and for whatever reason, re-typing the code in instead of copy & pasting it mafe the difference. 

good luck.

Message 32 of 39
eskimobo
in reply to: danvang

Thanks alot!

This is great stuff!

 

Due to the way we structure our constructions, I need a fixed and qnique position number for each part AND assembly. 

 

I have tried to add the attached code (at the buttom) right after your code writes to iProperties (both places).

But doing so gives me an Assy and part with the same position number, not accaptable.

 

Any Ideas on how I could do it?

 

 

    Dim Pos As String
    Pos = oBOMRowPO.ItemNumber
    
    iProperties.Value(CompFileNameOnly, "Custom", "#Pos") = Pos
Message 33 of 39

Hey mate,

the code is giving me this error - Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL)).

No idea why. Could you please help me out here

Message 34 of 39

Hi ,

That error is very generic. There is a tab called more info which might explain more. Can you also post the code your using in case some modification has been done. Also you can try step through the code with a messagebox/logger and  check where the code fails. You can also try bring back an object filename or iproperty through the same method.   

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

I copy pasted the code without any changes. 

Message 36 of 39

The code as written cannot handle writing an iProperty to a Content Center file/Library file. This is due to them being Read Only. To handle this error case you can use a Try Catch End Try statement.

        Try
            iProperties.Value(CompFileNameOnly, "Custom", "cQty") = Qty
	Catch 'Is Not a writeable file
End Try

  

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

Hey mate this code was really helpful. I have a small request, if you get time to do it please. For frame members and content central structural members, the quantity is coming in length and not number of pieces after running the code. If there a line which can divide the quantity with unit quantity and then input the final answer in part quantity in custom iproperty for the part. 

If possible it would be a huge help. 

Message 38 of 39

Also, the code ran perfectly first time i used it. I added new parts and now it is not running. 

Message 39 of 39

I would suggest posting this in a new post and supplying a link fore reference.  You will get more eyes on it. Include the full rule and explain what your looking to achieve and what is currently the results. If there is error messages post the more info tab which should contain the rule name. From what I see your looking  to change the rules functionality which can get very messy in long old threads. Your adding new parts. However you will need to explain what type of parts content center, library parts, custom parts saved in workspsce etc.  

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

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report