Modify Schedule Definition

Hey all,

I’m trying to generate two schedules for each furniture item in a model. When creating the schedule, I apply a view template to it (to avoid heavy lifting code wise). I need to filter by type mark, so I’ve excluded that category from my view template. That’s where things are going wrong.

I keep getting errors related to fields not being present in the schedule.

If I run the script shown below as is, the error I get is: “Exception: The field ID is not the ID of a field in this ScheduleDefinition.
Parameter name: filter”

If I run the script with the commented out lines, the error I get is: “ValueError: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index”

If I run the script again, it will function as expected, but only for previously created schedules, which leads me to believe I need to convert the view to a DSType, but so far, that has done nothing for me…do I need to collect elements again? Should I create another node for editing after I’ve already created the schedules? If I use the method .GetFieldOrder() on the newly created schedules (after applying the view template) I still get an empty list. What am I doing wrong? Any help is greatly appreciated!

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReference('DSCoreNodes')
from DSCore import List

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

# The inputs to this node will be stored as a list in the IN variables.
fams = UnwrapElement(IN[0])
fieldnames = IN[1]
prefix = IN[2]
texttype = IN[3]
phase = IN[4]
phasevis = IN[5]
countschedules = []
optionschedules = []
output = []
errs = []

# collect existing schedules from model
collector = FilteredElementCollector(doc)
filter = ElementCategoryFilter(BuiltInCategory.OST_Schedules)
views = collector.WherePasses(filter).ToElements()
viewsnames = [view.Name for view in views]

# get or create(future functionality) view templates
for view in views:
	if (view.IsTemplate) and (view.Name == "FFE - Furniture Counts"):
		viewtemplate1 = view.Id
		filterfield1 = view.Definition.GetFieldOrder()[0]
		
	elif (view.IsTemplate) and (view.Name == "FFE - Furniture Options"):
		viewtemplate2 = view.Id
		filterfield2 = view.Definition.GetFieldOrder()[0]
		
# create schedules for each furniture item
TransactionManager.Instance.EnsureInTransaction(doc)
for fam in fams[0]:
	name = fam.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_MARK).AsString()
	schedule1name = prefix + " - " + name + " Counts"
	schedule2name = prefix + " - " + name + " Options"
	try:
		index1 = viewsnames.index(schedule1name)
		schedule1 = views[index1]
	except:
		schedule1 = ViewSchedule.CreateSchedule(doc,ElementId(-2000080))
		schedule1.Name = schedule1name
	try:
		index2 = viewsnames.index(schedule2name)
		schedule2 = views[index2]		
	except:
		schedule2 = ViewSchedule.CreateSchedule(doc,ElementId(-2000080))
		schedule2.Name = schedule2name
			
	viewphase1 = schedule1.get_Parameter(BuiltInParameter.VIEW_PHASE)
	viewphase1.Set(ElementId(phase))
	viewphase2 = schedule2.get_Parameter(BuiltInParameter.VIEW_PHASE)
	viewphase2.Set(ElementId(phase))
	
	schedule1.ViewTemplateId = viewtemplate1
	schedule1.LookupParameter("View Classification").Set("FFE")
	schedule2.ViewTemplateId = viewtemplate2
	schedule2.LookupParameter("View Classification").Set("FFE")
	
	#filterfield1 = schedule1.Definition.GetFieldOrder()[0]
	#filterfield2 = schedule2.Definition.GetFieldOrder()[0]

	existfilters1 = schedule1.Definition.GetFilters()
	existfilters2 = schedule2.Definition.GetFilters()
	filtertype = ScheduleFilterType().Equal
	if existfilters1.Count > 0:
		existfilters1[0].SetValue(name)
	else:
		filter1 = ScheduleFilter(filterfield1, filtertype, name)
		schedule1.Definition.AddFilter(filter1)
	if existfilters2.Count > 0:
		existfilters2[0].SetValue(name)
	else:
		filter2 = ScheduleFilter(filterfield2, filtertype, name)
		schedule2.Definition.AddFilter(filter2)

		countschedules.append(schedule1.ToDSType(True))
		optionschedules.append(schedule2.ToDSType(True))
TransactionManager.Instance.TransactionTaskDone()
# Assign your output to the OUT variable.
OUT = countschedules, optionschedules
1 Like

Hello @hrasmussen

try this method (find the corresponding field by Name in list of Schedulable Field)

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# Import DocumentManager and TransactionManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

# Import RevitAPI
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *


def findFieldByName(scheduleDef, fieldName):
	fieldIds = scheduleDef.GetFieldOrder()  
	for fieldId in fieldIds:
		if scheduleDef.GetField(fieldId).GetSchedulableField().GetName(doc) == fieldName:
			return fieldId
	return None  

templateSchedule1 =  UnwrapElement(IN[0])
scheduleToSet =  UnwrapElement(IN[1])


TransactionManager.Instance.EnsureInTransaction(doc)
#get Name of ScheduleField from Template
templ_scheduleDef1 = templateSchedule1.Definition
fieldId1 = templ_scheduleDef1.GetFieldOrder()[0]
scheduleFieldTName1 = templ_scheduleDef1.GetField(fieldId1).GetSchedulableField().GetName(doc)

#from Schedule Instance create filter
scheduleDefToSet = scheduleToSet.Definition
searchFieldId = findFieldByName(scheduleDefToSet, scheduleFieldTName1)
newSchFilter1 = ScheduleFilter(searchFieldId, ScheduleFilterType.Equal, "Test")
scheduleDefToSet.AddFilter(newSchFilter1)
TransactionManager.Instance.TransactionTaskDone()

OUT = scheduleDefToSet

2 Likes