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