I'm trying to create a new document from a template when another object enters a specific workflow state. I couldn't find a way to easily create the document from the template so I am trying to use the information on copying a file on the following page:
https://developer.m-files.com/Samples-And-Libraries/Samples/Processes/Copying-Objects/
The code below performs the following actions:
- Finds the template.
- Copies the properties.
- Removes unnecessary properties. I had a shorter list but I removed all the unnecessary ones trying to troubleshoot this issue.
- Change some of the remaining properties.
- Copy the files in the template to a new SourceObjectFiles object.
- Rename the file. There's only one in this example.
- Copy the ACL.
- Create the new object/file.
- Delete the temporary files from the server.
Every step goes through without errors. I've verified all the objects that I'm passing to the CreateNewObjectExQuick have good data in them. The function returns an ID for the newly created document. However, nothing is actually created. I cannot see anything in M-Files and the logs don't show that anything has been created.
The documentation for the CreateNewObjectExQuick function state "if the source file(s) cannot be uploaded the newly created object is left checked out and cannot be accessed from the M-Files UI". This is the only clue that I have as to why it may not be working. However, I have verified all the data in the SourceObjectFiles object is accurate and pointing to the correct files in the Temp folder. M-Files is able to access the folder because I see the file created then removed. I have even tried the original CreateNewObject function, then checked in the object, with the same results.
I'm at a loss. Does anyone have any ideas?
OPTION EXPLICIT
'# Define M-Files Property IDs #
DIM ARCHIVE_STATUS_ID : ARCHIVE_STATUS_ID = Vault.PropertyDefOperations.GetPropertyDefIDByAlias("PD.ArchiveStatus")
DIM DOCTYPE_ID : DOCTYPE_ID = Vault.PropertyDefOperations.GetPropertyDefIDByAlias("PD.DocumentType")
DIM JOB_NUMBER_ID : JOB_NUMBER_ID = Vault.PropertyDefOperations.GetPropertyDefIDByAlias("JobNumber")
DIM SALES_ORDER_ID : SALES_ORDER_ID = Vault.PropertyDefOperations.GetPropertyDefIDByAlias("SalesOrder")
'# Define M-Files Class IDs #
DIM ELECDOC_CLASS : ELECDOC_CLASS = Vault.ClassOperations.GetObjectClassIDByAlias("CL.ElectricalDocuments")
'# Create Archive Status Array #
Dim oArchiveStatus: Set oArchiveStatus = CreateObject("System.Collections.ArrayList")
oArchiveStatus.Add 57 '# Current #
'# Create Document Type Array #
Dim oDocumentType: Set oDocumentType = CreateObject("System.Collections.ArrayList")
oDocumentType.Add 174 '# Control Panel Checklist #
'# Create Search Conditions Object #
Dim oSearchConditions : Set oSearchConditions = CreateObject("MFilesAPI.SearchConditions")
'# Exclude Deleted Items #
oSearchConditions.Add -1, AddStatusSearchCondition(MFStatusTypeDeleted, MFConditionTypeEqual, MFDatatypeBoolean, False)
'# Add Electrical Documents Class to Search Conditions #
oSearchConditions.Add -1, AddPropertySearchCondition(MFBuiltInPropertyDefClass, MFConditionTypeEqual, MFDatatypeMultiSelectLookup, ELECDOC_CLASS)
'# Add Document Type Property to Search Conditions #
oSearchConditions.Add -1, AddPropertySearchCondition(DOCTYPE_ID, MFConditionTypeEqual, MFDatatypeMultiSelectLookup, oDocumentType)
'# Add Archive Status Property to Search Conditions #
oSearchConditions.Add -1, AddPropertySearchCondition(ARCHIVE_STATUS_ID, MFConditionTypeEqual, MFDatatypeMultiSelectLookup, oArchiveStatus)
'# Add IsTemplate Property to Search Conditions #
oSearchConditions.Add -1, AddPropertySearchCondition(MFBuiltInPropertyDefIsTemplate, MFConditionTypeEqual, MFDatatypeBoolean, True)
'# Get Search Results #
Dim oSearchResults : Set oSearchResults = Vault.ObjectSearchOperations.SearchForObjectsByConditions(oSearchConditions, 0, False)
If oSearchResults.Count = 0 Then
Err.Raise MFScriptCancel, "Could not find the Control Panel Checklist Template."
ElseIf oSearchResults.Count > 1 Then
Err.Raise MFScriptCancel, "Too many Control Panel Checklist Templates found. Only one template should be marked as 'Current'."
Else
'# Found Checklist Template. Create New Checklist from Template. #
Dim oChecklistTemplateObjVer : Set oChecklistTemplateObjVer = oSearchResults.Item(1).ObjVer
Dim oChecklistTemplateProperties : Set oChecklistTemplateProperties = Vault.ObjectPropertyOperations.GetProperties(oChecklistTemplateObjVer, True)
'# Copy Template Properties then Remove Unwanted Properties #
Dim oNewChecklistProperties : Set oNewChecklistProperties = oChecklistTemplateProperties.Clone
RemovePropertyValue oNewChecklistProperties, ARCHIVE_STATUS_ID
RemovePropertyValue oNewChecklistProperties, MFBuiltInPropertyDefAccessedByMe
RemovePropertyValue oNewChecklistProperties, MFBuiltInPropertyDefCreated
RemovePropertyValue oNewChecklistProperties, MFBuiltInPropertyDefCreatedBy
RemovePropertyValue oNewChecklistProperties, MFBuiltInPropertyDefIsTemplate
RemovePropertyValue oNewChecklistProperties, MFBuiltInPropertyDefLastModified
RemovePropertyValue oNewChecklistProperties, MFBuiltInPropertyDefLastModifiedBy
RemovePropertyValue oNewChecklistProperties, MFBuiltInPropertyDefMarkedForArchiving
RemovePropertyValue oNewChecklistProperties, MFBuiltInPropertyDefObjectChanged
RemovePropertyValue oNewChecklistProperties, MFBuiltInPropertyDefOriginalPath
RemovePropertyValue oNewChecklistProperties, MFBuiltInPropertyDefSizeOnServerThisVersion
RemovePropertyValue oNewChecklistProperties, MFBuiltInPropertyDefSizeOnServerAllVersions
RemovePropertyValue oNewChecklistProperties, MFBuiltInPropertyDefStatusChanged
'# Set Property Metadata Fields #
oNewChecklistProperties.SearchForProperty(JOB_NUMBER_ID).CloneFrom(PropertyValues.SearchForProperty(JOB_NUMBER_ID))
oNewChecklistProperties.SearchForProperty(MFBuiltInPropertyDefNameOrTitle).Value.SetValue MFDatatypeText, "Test Checklist Document"
oNewChecklistProperties.SearchForProperty(SALES_ORDER_ID).CloneFrom(PropertyValues.SearchForProperty(SALES_ORDER_ID))
'# Copy Checklist Template Files #
Dim oNewChecklistFiles : Set oNewChecklistFiles = GetObjectSourceFiles(oChecklistTemplateObjVer)
oNewChecklistFiles.Item(1).Title = "Test Checklist Document"
'# Copy Access Control List #
Dim oAccessControlList : Set oAccessControlList = Vault.ObjectOperations.GetObjectPermissions(oChecklistTemplateObjVer).AccessControlList.Clone
'# Create New Template in M-Files #
Dim bSingleFileDocument : bSingleFileDocument = oNewChecklistProperties.SearchForProperty(MFBuiltInPropertyDefSingleFileObject).Value.Value
Dim lNewID : lNewID = Vault.ObjectOperations.CreateNewObjectExQuick(oChecklistTemplateObjVer.Type, oNewChecklistProperties, oNewChecklistFiles, bSingleFileDocument, True, oAccessControlList)
'# Delete Temporary Files #
ClearTemporaryFiles(oNewChecklistFiles)
End If
Private Function AddPropertySearchCondition(iMFPropertyDef, iMFConditionType, iMFDataType, oSearchValue)
'#################################################
'# Purpose: Creates a SearchConditionEx object
'#
'# Parameters:
'# iMFPropertyDef - M-Files Property ID
'# iMFConditionType - M-Files MFConditionType Enumeration
'# iMFDataType - M-Files MFDataType Enumeration
'# oSearchValue - Value or Array of Values
'#################################################
Dim oSearchCondition : Set oSearchCondition = CreateObject("MFilesAPI.SearchCondition")
oSearchCondition.Expression.SetPropertyValueExpression iMFPropertyDef, MFParentChildBehaviorNone, Nothing
oSearchCondition.ConditionType = iMFConditionType
If VarType(oSearchValue) <> 9 Then
'# oSearchValue is not an Array #
oSearchCondition.TypedValue.SetValue iMFDataType, oSearchValue
Else
oSearchCondition.TypedValue.SetValue iMFDataType, oSearchValue.ToArray()
End If
Set AddPropertySearchCondition = oSearchCondition
End Function
Private Function AddStatusSearchCondition(iMFPropertyDef, iMFConditionType, iMFDataType, oSearchValue)
'#################################################
'# Purpose: Creates a SearchConditionEx object
'#
'# Parameters:
'# iMFPropertyDef - M-Files Property ID
'# iMFConditionType - M-Files MFConditionType Enumeration
'# iMFDataType - M-Files MFDataType Enumeration
'# oSearchValue - Value or Array of Values
'#################################################
Dim oSearchCondition : Set oSearchCondition = CreateObject("MFilesAPI.SearchCondition")
oSearchCondition.Expression.SetStatusValueExpression iMFPropertyDef, Nothing
oSearchCondition.ConditionType = iMFConditionType
oSearchCondition.TypedValue.SetValue iMFDataType, oSearchValue
Set AddStatusSearchCondition = oSearchCondition
End Function
Private Function GetObjectSourceFiles(oSourceObjVer)
Dim oFSO: Set oFSO = CreateObject("Scripting.FileSystemObject")
'# Get the Temporary Folder Path #
CONST TEMPFOLDER = 2 '# https://msdn.microsoft.com/en-us/library/a72y2t1c(v=vs.84).aspx #
Dim sTempFolderPath: sTempFolderPath = oFSO.GetSpecialFolder(TEMPFOLDER).Path
'# Get Files for Current ObjVer Object #
Dim oFiles: Set oFiles = Vault.ObjectFileOperations.GetFiles(oSourceObjVer)
' Create New SourceObjectFiles Collection #
Dim oSourceFiles: Set oSourceFiles = CreateObject("MFilesAPI.SourceObjectFiles")
'# Add Files to the New SourceObjectFiles Collection #
Dim iCounter
Dim oFile
For iCounter = 1 To oFiles.Count
Set oFile = oFiles.Item(iCounter)
'# Download Current File to Temp Folder #
Dim sTempFilePath: sTempFilePath = oFSO.BuildPath(sTempFolderPath, oFSO.GetTempName()) & "." & oFile.Extension
Vault.ObjectFileOperations.DownloadFile oFile.ID, oFile.Version, sTempFilePath
'# Create ObjectSourceFile for Current File #
Dim oObjectSourceFile: Set oObjectSourceFile = CreateObject("MFilesAPI.SourceObjectFile")
oObjectSourceFile.Extension = oFile.Extension
oObjectSourceFile.SourceFilePath = sTempFilePath
oObjectSourceFile.Title = oFile.Title
'# Add ObjectSourceFile to ObjectSourceFiles Collection #
oSourceFiles.Add -1, oObjectSourceFile
Next
'# Return ObjectSourceFiles Collection #
Set GetObjectSourceFiles = oSourceFiles
End Function
Private Sub ClearTemporaryFiles(oObjectSourceFiles)
Dim oFSO: Set oFSO = CreateObject("Scripting.FileSystemObject")
'# Delete the Files in the ObjectSourceFiles Collection from the Temp Folder #
Dim iCounter, oFile
For iCounter = 1 To oObjectSourceFiles.Count
Set oFile = oObjectSourceFiles.Item(iCounter)
If oFSO.FileExists(oFile.SourceFilePath) Then
On Error Resume Next
oFSO.DeleteFile oFile.SourceFilePath, True
On Error Goto 0
End If
Next
End Sub
Private Sub RemovePropertyValue(ByRef oPropertyValues, iPropertyDef)
'# Find Index of the Property Value (-1 if Not Found) #
Dim iIndex: iIndex = oPropertyValues.IndexOf(iPropertyDef)
If iIndex > -1 Then oPropertyValues.Remove iIndex
End Sub
