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
Solved! Go to Solution.
Solved by danvang. Go to Solution.
Solved by danvang. Go to Solution.
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
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
Upload what you have and I can take a look later tonight.
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
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
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
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.
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.
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
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
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.
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
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.
Also, the code ran perfectly first time i used it. I added new parts and now it is not running.
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.