Announcements
Attention for Customers without Multi-Factor Authentication or Single Sign-On - OTP Verification rolls out April 2025. Read all about it here.

How can I get the Item Quantity from a Structured or Model Data BOM View over all levels, Iterate Rows but how.

checkcheck_master
Advocate

How can I get the Item Quantity from a Structured or Model Data BOM View over all levels, Iterate Rows but how.

checkcheck_master
Advocate
Advocate

I know how to do a for each on all the BOM rows and compare the value with what I'm looking for.

But that level is not deep enough do I need to dive in the Child Rows I suppose.

I've tried that without success .

In other rules I've used iterate rows with succes.

I think my main issue is that I do not know/understand what to do too make the existing rule iterate.

It seems correct that you have to assign the BOM in another sub as the iterate function or sub?

Please help. 

 

Function RecurseBOMRow(oBOMRows As BOMRowsEnumerator, Component As Document) As Integer
   For Each oBOMRow In oBOMRows'.ChildRows
     Dim oCompDef As ComponentDefinition
     oCompDef = oBOMRow.ComponentDefinitions.Item(1)

    	If oCompDef.Document.FullFileName Like Component.FullFileName Then
			QTY = oBOMRow.ItemQuantity()
'			sw.WriteLine("Match: " & "oBOMRow.ItemQuantity: " & oBOMRow.ItemQuantity)
			Return QTY
			Exit Function
		End If	
	 
	 'Call SetRowProps(oCompDef, oBOMRow.TotalQuantity)

     If Not oBOMRow.ChildRows Is Nothing
          Call RecurseBOMRow(oBOMRow.childrows, Component)
     End If
   Next
End Function
Function GetQTY_StructuredBOM(oDoc As Document, Component As Document)As Integer

	Dim oAssyDef As AssemblyComponentDefinition = oDoc.ComponentDefinition
	Dim oBOM As BOM = oAssyDef.BOM
	
	oBOM.StructuredViewEnabled = True
	oBOM.StructuredViewFirstLevelOnly = False
	
	'oBOM.PartsOnlyViewEnabled = True
	
	'Dim oBOMView As BOMView = oBOM.BOMViews.Item(1) ' Model Data, see also Phantom Assemblies
	Dim oBOMView As BOMView = oBOM.BOMViews.Item("Structured")
	'Dim oBOMView As BOMView = oBOM.BOMViews.Item("Parts Only")
	
	'RecurseBOMRow(oBOMView.BOMRows, Component)	
		
	Dim oBOMRow As BOMRow
	Dim oCompDef As ComponentDefinition
	
'	sw.WriteLine("")
'	sw.WriteLine("GetQTY_StructuredBOM")
'	sw.WriteLine("Search BOMrows in doc: " & oDoc.DisplayName)
'	sw.WriteLine("Search for Comp: " & Component.FullFileName)
'	sw.WriteLine("BOMRows.Count: " & oBOMView.BOMRows.Count)
'	sw.WriteLine("")
		
	If Component.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
	
		RecurseBOMRows(oBOMView.BOMRows, oDoc, Component)
	
	End If
	
'''''	For Each oBOMRow In oBOMView.BOMRows	
		
'''''    	' Set a reference to the primary ComponentDefinition of the row
'''''		oCompDef = oBOMRow.ComponentDefinitions.Item(1)
		
''''''			Dim QTY_Of_Item As String
''''''			QTY_Of_Item = oBOMRow.ItemQuantity()
							
''''''			Dim Path_And_File_Name As String
''''''			Path_And_File_Name = oCompDef.Document.FullFileName
							
''''''			Dim BOM_Structure As String
''''''			BOM_Structure = oBOMRow.BOMStructure
							
''''''			List = List & vbCrLf & QTY_Of_Item & " - " & Path_And_File_Name & " - " & BOM_Structure
''''''			sw.WriteLine(List)
		
'''''		If oCompDef.Document.FullFileName Like Component.FullFileName Then
'''''			QTY = oBOMRow.ItemQuantity()
'''''			sw.WriteLine("Match: " & "oBOMRow.ItemQuantity: " & oBOMRow.ItemQuantity)
'''''		End If
		
''''''		If Not oBOMRow.ChildRows Is Nothing Then
			
''''''	     Call GetQTY_StructuredBOM(oBOMRow.ChildRows, indent +2,"","")
''''''	    End If
		
'''''	Next
	
	'MsgBox(List)
	
	'sw.WriteLine("QTY AT END GetQTY_StructuredBOM : " & QTY & " " & oDoc.DisplayName)
	
	Return QTY
		
End Function

 

0 Likes
Reply
817 Views
5 Replies
Replies (5)

WCrihfield
Mentor
Mentor

Hi @checkcheck_master.  I'm sure there are other similar examples out there, but this is an example of one that I have used before.  The Sub being used is fairly similar to your first Function code.  I simplified the Sub Main code just for this example, so I'm sure you will want to use a different means to specify which document you want to find the total quantity of.  And of course there are other ways of doing something like this, without using the BOM, depending on your specific requirements and the details of your scenario.

 

Sub Main
	If ThisApplication.ActiveDocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
		MsgBox("An Assembly Document must be active for this rule to work. Exiting.", vbCritical, "")
		Exit Sub
	End If
	Dim oADoc As AssemblyDocument = ThisApplication.ActiveDocument
	oBOM = oADoc.ComponentDefinition.BOM
	oBOM.StructuredViewEnabled = True
	oBOM.StructuredViewFirstLevelOnly = False
	oBOMView = oBOM.BOMViews.Item("Structured")
	Dim oDocToCountQtyOf As Document = oADoc.ReferencedDocuments.Item(3)
	Dim oTotalQty As Integer = 0
	ProcessBOMRowsRecursively(oBOMView.BOMRows, oDocToCountQtyOf, oTotalQty)
	MsgBox("Total Quantity found = " & oTotalQty, , "")
End Sub

Sub ProcessBOMRowsRecursively(oBOMRows As BOMRowsEnumerator, oDocToFind As Document, ByRef oTotalQty As Integer)
	For Each oRow As BOMRow In oBOMRows
		If oRow.BOMStructure = BOMStructureEnum.kPhantomBOMStructure Or _
			oRow.BOMStructure = BOMStructureEnum.kReferenceBOMStructure Then
			Continue For
		End If
		Dim oCD As ComponentDefinition = Nothing
		oCD = oRow.ComponentDefinitions.Item(1)
		If TypeOf oCD Is VirtualComponentDefinition Then Continue For
		Dim oRowDoc As Document = Nothing
		oRowDoc = oCD.Document
		If oRowDoc Is oDocToFind Then
			oTotalQty = oTotalQty + oRow.ItemQuantity
			'oTotalQty = oTotalQty + oRow.TotalQuantity
		End If
		If Not oRow.ChildRows Is Nothing Then
			ProcessBOMRowsRecursively(oRow.ChildRows, oDocToFind, oTotalQty)
		End If
	Next
End Sub

 

Sometimes I choose to use an additional Sub or Function to do the core functionality, then simply call that one within my recursive routine, in order to keep the recursive routine simpler and cleaner looking.  But that's just situational preference.

 

Edit:  I mistakenly posted an older version of the code as a Function earlier, then updated the code to the new Sub version later.  I often have several versions of some of my codes stored in various places.  Sometimes I did not change their names and get older versions confused with newer versions.  I've got to do some house cleaning on my file system. :face_with_rolling_eyes:

 

If this solved your problem, or answered your question, please click ACCEPT SOLUTION.
Or, if this helped you, please click (LIKE or KUDOS) :thumbs_up:.

If you want and have time, I would appreciate your Vote(s) for My IDEAS :bulb: or you can Explore My CONTRIBUTIONS

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes

checkcheck_master
Advocate
Advocate

Thanks WCrihfield, I'll check it out right away.
What are your thoughts on retrieving Parent document and Parent document BomStructure from the BOMView?
What do you think is the best method?

This is what I used now but I'm wondering if there is any better.

For Each oBOMRow In oBOMRows
    ' Let's only get the first definition
    ' It would only be more than one if rows were merged
    Dim oDef As ComponentDefinition
    oDef = oBOMRow.ComponentDefinitions(1)
			
	Dim partNumber As String
	    partNumber = oDef.Document.PropertySets("{32853F0F-3444-11D1-9E93-0060B03C1CA6}")("Part Number").value
		Dim oDoc As Document = oBOMRow.ComponentDefinitions.Item(1).Document	
	
		Dim Parent As Document = oDoc.ReferencingDocuments.Item(1)
		Dim oParentDocFile As Document
		oParentDocFile = Parent	
		BOM_Parent = GetBOMStructure(oParentDocFile.ComponentDefinition.BOMStructure)
	 	 
	 'If GetBOMStructure(oBOMRow.BOMStructure) Like filter Or GetProp(oDoc, "IUDP", "Fabrication") Like "*W*" Then
	 'If GetProp(oDoc, "IUDP", "Fabrication") Like "*W*" Then
	 If oBOMRow.ComponentDefinitions.Item(1).Document.FullFileName Like "**" Then	
		


One more question, if I want to show all the properties but some don't exist, is there a standard way to have it so no error message or should I make a Sub with a Try Catch in it?

I don't like a whole pile of try catches
And what is the best method to retrieve them, is there a right or wrong, is one more stable than the other?

With a separate sub I can show when the code has no value.

0 Likes

checkcheck_master
Advocate
Advocate

One more question I'd like to ask you.
When I'm going through the BOM View and want to collect/put an Assembly with all its child parts in a separate folder.
What is the best method for that?
Recursively run through the assembly based on Occurrences or through the Child Rows of the BOM.
What are the pros and cons of this or maybe there is something better.

0 Likes

WCrihfield
Mentor
Mentor

Hi @checkcheck_master.  Document parent is sort of the wrong terminology for what we are looking for, but even what we are looking for here is like smoke and mirrors.  Sometimes it does not exist...sometimes if there should be one, it will not be found...sometimes there will be multiple and will return the wrong one.  Even though the Document object has a Parent property, its value is a generic Object, and will usually just return the Application object, instead of whatever assembly document or component definition this document may be directly referenced within as a component.  Using the Document.ReferencingDocuments route, depends on the higher level documents being currently either initialized or open (in-memory) to find them, then if the document is more than one level deep in an assembly, it may return the top level assembly along with every other sub assembly it is in above that point, and it may not be obvious which one of the multiple to choose without seeing the list and choosing the right one.

 

In my test using the iLogic code below and a testing assembly document, I chose a part that was within a weldment sub assembly, and that weldment was a top level component.  In this situation, the top level assembly, and the weldment sub assembly were both in the list of documents referencing the part, but the weldment sub assembly was the second one in the list, not the first.  (Components representing that part were also within the top level of the assembly.)  Here is the code I used for that test.

Dim oADoc As AssemblyDocument = ThisDoc.Document
oADef = oADoc.ComponentDefinition
oOccs = oADef.Occurrences
'top level sub assembly weldment
oTopOcc = oOccs.ItemByName("Weldment BOM sample:1")
'part within that sub assembly
oSubOcc = oTopOcc.Definition.Occurrences.ItemByName("Part1:1")
Dim oSubOccDoc As Document = oSubOcc.ReferencedDocumentDescriptor.ReferencedDocument
Dim oParentDoc As Document = Nothing
'this won't work...returns Application
'oParentDoc = oSubOccDoc.Parent
oUpRefDocs = oSubOccDoc.ReferencingDocuments
If oUpRefDocs.Count = 0 Then
	MsgBox("No In-Memory Documents found referencing this doc.", , "")
ElseIf oUpRefDocs.Count = 1 Then
	oParentDoc = oUpRefDocs.Item(1)
ElseIf oUpRefDocs.Count > 1 Then
	'oParentDoc = oUpRefDocs.Item(1)
	'or
	Dim oUpRefDocNames As New List(Of String)
	For Each oUpRefDoc As Document In oUpRefDocs
		oUpRefDocNames.Add(oUpRefDoc.FullDocumentName)
	Next
	oUpRefDocName = InputListBox("", oUpRefDocNames, "", "Referencing Documents", "List Of Referencing Documents")
	For Each oUpRefDoc As Document In oUpRefDocs
		If oUpRefDoc.FullDocumentName = oUpRefDocName Then
			oParentDoc = oUpRefDoc
		End If
	Next
End If
If oParentDoc Is Nothing Then
	MsgBox("No 'Parent' doc found.", , "")
Else
	Dim oBOMStr As BOMStructureEnum = oParentDoc.ComponentDefinition.BOMStructure
	MsgBox("'Parent' doc name = " & oParentDoc.FullDocumentName & vbCrLf & _
	"and its BOMStructure is set to " & oBOMStr.ToString, , "")
End If

Pertaining to checking iProperties:

As far as retrieving several iPropeties from multiple documents and the right process for it to avoid errors...I would have to say that if it can be done without using a Try...Catch block and still avoid errors, then that is likely the best route, but if you don't know of any other way to avoid expected potential errors, then use the Try...Catch block.  In cases concerning things like Parameters & iProperties, you can usually just loop through them to find whether or not the parameter or property exists, either using something like a Boolean variable, or a pre-defined variable to hold the found object.  Then after the loop, check your Boolean or your variable to see if it is False or Nothing.  That is often the better alternative, when possible, instead of a Try...Catch block.  However, I generally advise folks to keep the contents within the Try...Catch block as brief, simple, and to the point as possible.  Just the one problem line, or just the few lines that are testing an error prone object/method.  And I also generally advise folks to make use of the Catch side, instead of just leaving it empty.  Even if it's just to write something about the error to the logger in the background.  It can be a huge help if/when you need to debut problems later.

 

Pertaining to putting an assembly and its children into a folder, and possible iteration techniques:

I assume you are talking about a BrowserFolder in the model BrowserPane?  I would assume that when you move the assembly into a folder that all its children would also automatically stay with the assembly, into the folder, unless I'm missing some sort of special detail.  As far as which iteration process is best...it is probably just a personal preference, rather than necessity or advantage in many situations, but I suppose if you are looking for quantities, then that's part of what the BOM is for, so that might be a more logical choice.  For most other tasks I personally usually prefer iterating the assembly by either its ReferencedDocuments or its Occurrences, depending on what I'm trying to accomplish.  But I generally just don't need to work with the BOM by code as heavily or with as much customization as a lot of others, so I may be leaning that way due to being far more familiar with it.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes

checkcheck_master
Advocate
Advocate

Thanks WCrihfield, you have provided me with a lot of valuable information, you don't want to know how happy I am with this.

 

I conclude that I have to be very careful with using Parent relations to make certain subdivisions or not, thanks for this insight.
It's also good to see this confirmed, sometimes I doubt whether I'm observing it correctly.
For example, we use a Phantom assembly with Weldments to get all underlying sub-weldment assemblies in a physical folder.
I determined on the basis of the parent relation whether it had to do with such a folder.
I'm going to use a custom property for that that controls that.
Much more flexible too.

 

In response to your question 'I assume you are talking about a BrowserFolder in the model BrowserPane?':
No, I mean a physical Directory.
I think I have enough information to fill that in.
Krieg already advised me to work from the BOMView.
That's what I'm going for for now.

 

With regard to Inseparable assemblies, to date we have not worked there with the argument that parts no longer appear on a total Parts Only list.
This from the point of view/demand from a supplier who wants an overview of all parts to be delivered.
When welding assemblies are Inseparable, in my opinion a simple Parts Only list will suffice to collect the other parts.
How do you view that?

0 Likes