Edit UDP during Lifecycle transition

Edit UDP during Lifecycle transition

christian_skare
Enthusiast Enthusiast
90 Views
3 Replies
Message 1 of 4

Edit UDP during Lifecycle transition

christian_skare
Enthusiast
Enthusiast

Hi,

I attempting to programmatically update the Checked By and Approved By properties pre lifecycle change.

 

I've managed to create something that checks current LC and next LC, and then trigger SetVaultProperty that shall do the property changes.

But I'm completely stuck on how to update/keep the properties.

 

Currently I'm able to check the file out, update the property, check the file in. But during Check In the property changes is reverted.

 

LifeCycleStateEvent

private void UpdateFileLifecycleStateEvents_Pre(object sender, UpdateFileLifeCycleStateCommandEventArgs e)
{
    // Get the service context from sender
    IWebService service = sender as IWebService;
    if (service == null)
    {
        MessageBox.Show("Service is null", "Debug", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }

    // Create credentials and manager for this session
    WebServiceCredentials cred = new WebServiceCredentials(service);
    using (WebServiceManager mgr = new WebServiceManager(cred))
    {
        for (int i = 0; i < e.FileMasterIds.Length; i++)
        {
            long masterId = e.FileMasterIds[i];
            
            try
            {
                var file = mgr.DocumentService.GetLatestFileByMasterId(masterId);

                if (file == null)
                {
                    MessageBox.Show($"No file found for Master ID: {masterId}", "Debug", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    continue;
                }
                                       
                var currentState = file.FileLfCyc.LfCycStateName;
                long toStateId = e.ToStateIds[i];
                                                               
                var lfcDefId = file.FileLfCyc.LfCycDefId;
                var lfcDef = mgr.LifeCycleService.GetLifeCycleDefinitionsByIds(new long[] { lfcDefId }).FirstOrDefault();
                var toState = lfcDef?.StateArray.FirstOrDefault(s => s.Id == toStateId);
                var targetStateName = toState?.DispName ?? "(unknown)";
                                       
                if (currentState == "For Checking" && targetStateName == "For Approval")
                {
                   SetVaultProperty(mgr, file, "Checked By", cred.Session.User.Name);
                }
                else if (currentState == "For Approval" && targetStateName == "Approved")
                {
                    SetVaultProperty(mgr, file, "Mfg Approved By", cred.Session.User.Name);
                }
                else if (currentState == "Work In Progress" && targetStateName == "For Approval")
                {
                    SetVaultProperty(mgr, file, "Checked By", "-");
                }
                else if (currentState == "Work In Progress" && targetStateName == "Approved")
                {
                    SetVaultProperty(mgr, file, "Checked By", "-");
                    SetVaultProperty(mgr, file, "Mfg Approved By", cred.Session.User.Name);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Exception: {ex.Message}\n{ex.StackTrace}", "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
}

 

SetVaultProperty (updating the properties, but these are lost during checkin)

private void SetVaultProperty(WebServiceManager mgr, File file, string propertyName, string value)
{
    MessageBox.Show($"Setting property '{propertyName}' to '{value}' for file '{file.Name}' (ID: {file.Id})", "Vault Lifecycle Extension", MessageBoxButtons.OK, MessageBoxIcon.Information);

    var propDefs = mgr.PropertyService.GetPropertyDefinitionsByEntityClassId("FILE");
    var targetDef = propDefs.FirstOrDefault(p => p.DispName.Equals(propertyName, StringComparison.OrdinalIgnoreCase));

    MessageBox.Show($"Property definition found: {targetDef?.DispName ?? "None"}", "Vault Lifecycle Extension", MessageBoxButtons.OK, MessageBoxIcon.Information);

    if (targetDef != null)
    {
        string localPath = System.IO.Path.Combine(@"C:\Vault", file.Name);
        ByteArray downloadTicket;

        // Checkout the file
        mgr.DocumentService.CheckoutFile(
            file.Id,
            CheckoutFileOptions.Master,
            Environment.MachineName,
            localPath,
            "Checked out to update properties during Lifecycle State Transition",
            out downloadTicket
        );
        MessageBox.Show($"File '{file.Name}' checked out for property update.", "Vault Lifecycle Extension", MessageBoxButtons.OK, MessageBoxIcon.Information);

        // Update the property
        var propArray = new PropInstParamArray
        {
            Items = new PropInstParam[] { new PropInstParam { PropDefId = targetDef.Id, Val = value } }
        };
        mgr.DocumentService.UpdateFileProperties(new long[] { file.MasterId }, new PropInstParamArray[] { propArray });


        // Check in the file using the upload ticket
        mgr.DocumentService.CheckinUploadedFile(
            file.MasterId,
            "Checked in via Admin Tools",
            false,                          // keepCheckedOut
            DateTime.Now,                   // lastWrite
            null,                           // associations
            null,                           // bom
            false,                          // copyBom
            file.Name,                      // newFileName
            file.FileClass,                 // fileClassification
            false,                          // hidden
            null                    // uploadticket
        );
        MessageBox.Show($"File '{file.Name}' checked in after property update.", "Vault Lifecycle Extension", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    else
    {
        MessageBox.Show($"Property definition not found for '{propertyName}'.", "Vault Lifecycle Extension", MessageBoxButtons.OK, MessageBoxIcon.Warning);
    }
}

 

Thanks in advance for any help.

0 Likes
Accepted solutions (1)
91 Views
3 Replies
Replies (3)
Message 2 of 4

Markus.Koechl
Autodesk
Autodesk
Accepted solution

You need to leverage the post-event to update properties. There are two reasons: first, the workflow gets reliable, and properties change on successful transitions only. Secondly, the iteration id changes if you update the file before the transition. That's the reason you see your changes reverted.



Markus Koechl

Solutions Engineer PDM, Autodesk Central Europe
0 Likes
Message 3 of 4

christian_skare
Enthusiast
Enthusiast

Thanks Markus,

I'm assuming your reply wouldve solved my issue, and accept it as a solution.

 

However,

I've been able to update the properties I want with a different approach, which seems to work almost perfect, except the built in PDF generation seem to run before the revision block syncronization.

 

When I transition from 'For Approval' → 'Approved' state, it creates a PDF before it syncronizes my properties to the drawing. Do I need to create a custom job to set the priority lower on the PDF generation?

 

Post event (need Post event since 'Approved' is locked for modification):
Lifecycle 'Approved' → 'Revision'

Clears properties, no longer checked and approved etc.

 

Pre Event (same as in original post):
All other state transitions.

 

Update properties:

private void SetVaultProperties(WebServiceManager mgr, WebServiceCredentials cred, File file, Dictionary<string, object> properties)
{

    // TODO: Get Connection from LogOn event instead of creating a new
    var propDefs = mgr.PropertyService.GetPropertyDefinitionsByEntityClassId("FILE");
    var propDict = new Dictionary<Autodesk.Connectivity.WebServices.PropDef, object>();

    foreach (var property in properties)
    {
        var targetDef = propDefs.FirstOrDefault(p => p.DispName.Equals(property.Key, StringComparison.OrdinalIgnoreCase));
        if (targetDef != null)
        {
            propDict[targetDef] = property.Value;
        }
        else
        {
            MessageBox.Show($"Property definition not found for '{property.Key}'.", "Vault Lifecycle Extension", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
    }

    if (propDict.Count == 0)
        return;

    try
    {
        var results = Library.ConnectionManager.LogIn(
            "Server",       // Server
            "Vault",            // Vault
            "Administrator",    // User
            "",                 // Password
            AuthenticationFlags.Standard,
            null);

        if (!results.Success)
            return;

        var connection = results.Connection;

        var explorerUtil = ExplorerLoader.LoadExplorerUtil(
            connection.Server,
            connection.Vault,
            connection.UserID,
            connection.Ticket);

        // Only one call for all properties
        explorerUtil.UpdateFileProperties(file, propDict);
    }
    catch (Exception ex)
    {
        MessageBox.Show($"Failed to update properties: {ex.Message}", "Vault Lifecycle Extension", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

 

Bonus question:
I want to reuse my connection to Vault instead of creating a new one every time.

This thread helped me to get in the right direction, but the OnLogOn event is never fired.

Solved: Getting Existing Vault Connection Through API - Autodesk Community

    public class ExplorerExtension : IExplorerExtension
    {
        public void OnLogOn(IApplication application)
        {
            MessageBox.Show("Vault Explorer LogOn event triggered.");
            // This messagebox never fires.
        }

 

 

0 Likes
Message 4 of 4

Markus.Koechl
Autodesk
Autodesk

Hi @christian_skare : I am glad to see you found a solution. To complete the feedback on your findings, an alternative solution for editing locked files triggered by the post-event involves using a secondary login (with similar or the same rights as a job processor user). Named user licensing allows to use of a secondary login; the sample collection demonstrates how to implement it.
Your bonus question: The log-on event is a Vault client-only event and is not available in Inventor-Vault.



Markus Koechl

Solutions Engineer PDM, Autodesk Central Europe
0 Likes