SoftPro Select IAttachment Cheat Sheet

SoftPro order can have documents attached to the folder in any collection of folders you find useful. This page will be a collection of ways to interact with attachment files, folders, and items with IronPython. This is a frequent ask so the Automation Snippets can perform logic in this area.

Typical Imports including LINQ Imports

These are the imports needed to run these examples. Not every Python fragment may need all the imports. Notice that since this is IronPython, I did include the library references for .NET LINQ extensions.

from System import *
from SoftPro.ClientModel import *
from SoftPro.Select.Client import *
from SoftPro.OrderTracking.Client.Orders import *
import System.Diagnostics as SD

# Include LINQ
import clr
import System
clr.AddReference('System.Core')
clr.ImportExtensions(System.Linq)

Get an IAttachmentFolder from a Path String

This function will take a list of attachment folder path strings and return the IAttachmentFolder objects for them. If any item in the input list is None, not a string, or not a valid folder, it will return None.

# Create the IAttachmentFolder by starting with the top level order folder and
#	walking down the items chain until we find it.
#
# Input string: "Title\\Other"
# Output IAttachementFolder: "\\Attachments\\Title\\Other"
# 	Note: If folder does not exist in order, returns None.
def GetAttachmentFolderFromPartialPath(folder):
	retFolder = IOrder.Attachments.GetValue(Context)
	
	# If requested folder None, return None.
	if folder is None or not isinstance(folder, str):
		return None

	# If requested folder is empty string, return the top level folder.
	if folder.strip() == "":
		return retFolder

	# Split the folder into strings separated by "\\" character and walk down the items.
	for subfolder in folder.split("\\"):
		if subfolder is None or not subfolder:
			break
			
		try:
			# If error detected (such as folder path doesn't exist, capture exception and return None.
			retFolder = (IAttachmentFolder.Items.GetValue(retFolder)
				.Where(lambda s: s.Name == subfolder and isinstance(s, IAttachmentFolder))
				.FirstOrDefault())
		except Exception:
			retFolder = None
			break
	
	# Return attachment folder we found (or possible None if we had errors.
	return retFolder

Delete all IAttachmentFiles in an IAttachmentFolder

This function takes a list of folders and delete all files from them. Note that we check to make sure the item is a file before we delete it by using the Python function isinstance(object, type).

# Delete all files from passed attachment folder list.
#	Does not alter folders or child folders.
def DeleteFilesInFolder(folders):
	# Validate input folder is attachment folder.
	if folders is None or not folders:
		return
	
	# Handle a list of one or more folders.
	for folder in folders:
		# Make sure item is a folder else skip it.
		if not isinstance(folder, IAttachmentFolder):
			continue
		
		# Must convert enumerator to list since deleting an item is not valid in an enumerated list.
		items = IAttachmentFolder.Items.GetValue(folder).ToList()
		for item in items:
			# Delete file.
			if isinstance(item, IAttachmentFile):
				IAttachmentFolder.DeleteItem(folder, item)

Another example of deleting only files from folder. In this case, the function is passed a single IAttachmentFolder object. This method does not use LINQ – only pure Python list comprehensions.

# Delete all files in passed IAttachmentFolder.
#    Do not alter folders nor descend into child folders.
def DeleteFilesFromFolder(folder):

	# Validate folder object.
	if folder is None:
		return

	# Get list of all files in folder.
	#    If item in folder is a file, "isinstance" will return True.
	files = [f for f in folder.Items if isinstance(f, IAttachmentFile)]

	# Delete any files - one by one.	
	for file in files:
		folder.DeleteItem(file)