Skip to main content
Automatic Revision Numbering

This article explains how to configure automatic file revision numbering based on its attribute details, via groovy scripts.

Updated over a week ago

Asite Visual Workflow enables users to configure automatic file revision numbering based on its attribute details, via groovy scripts. Below is an example scenario to understand how this works.

Let's take an example of a project wherein automatic file revision numbering is to be configured based on a combination of purpose of issue and status. Considering that this project has below purpose of issues and file statuses configured. Also mentioned below is the expected automatic revision number sequence (based on the corresponding combination of purpose of issue and status).

In the below example, revision numbers starting with P can be considered as internal revision numbers while the ones starting with C can be considered as external revision numbers.

Purpose of Issue

Status

Revision Number

S0

Work In Progress

P01.01, P01.02,… P01.0n

S0 (Update Only)

Work In Progress

(Same as per previous 'Work In Progress' version)

S1

Approved as Internal Share

For External Share

P01.01, P01.02,… P01.0n

S2

Approved as Internal Share

For External Share

P01.01, P01.02,… P01.0n

S3

Approved As External Shared

P01, P02,… P0n

P1

For Publishing

P01, P02,… P0n

P2

For Publishing

P01, P02,… P0n

A1

Authorized as Published

C01, C02,… C0n

To achieve the automatic file revision numbering in this example, user has to follow below steps:

Step 1: Configure a file system task for executing the groovy script. Below is an example groovy script that needs to be configured as a file system task.

def execute() {

//********************* Configurable parameter section *********************************

String pattern = "P";

String startNumber = "01";

String patternForPublishedRevision = "C";

String startNumberForPublishedRevision = "01";

// Status & POI list to set & update Minor Rev ** // P01.01, P01.02, P01.n...

String poiForMinorIncrement = "S0";

String statusForMinorIncrement = "Work In Progress";

String poiUpdateOnly = "S0 (Update Only)";

String poiForMinorUpdateOnly = "S1|S2";

String statusForMinorUpdateOnly = "Approved as Internal Share,For External Share";

// Status & POI list to set & update Major Rev ** // P01, P02, Pn...

String poiForMajorIncrementSet1 = "S3";

String statusForMajorIncrementSet1 = "Approved as External Shared";

String poiForMajorIncrementSet2 = "P1|P2";

String statusForMajorIncrementSet2 = "For Publishing";

// Status & POI list to set & update // C01, C02, Cn...

String poiForPublishIncrement = "A1|A2";

String statusForPublishIncrement = "Authorized as Published";

//********************* Configurable parameter section (END) *********************************

DocumentVO documentVO = documentService.getDocumentDetails();

ArrayList<DocumentVO> documentsList = new ArrayList<DocumentVO>();

HashMap<Object, Object> optionMap = new HashMap();

optionMap.put(RevisionOption.GET_REVISIONS, RevisionOption.ALL_REVISION);

optionMap.put(RevisionDetailsOption.BASIC_DETAILS, true);

optionMap.put(RevisionOption.INCLUDE_DEACTIVATED, true);

Map<String, DocumentVO> revisionsMap = documentService.getDocumentRevisionDetail(documentVO, optionMap);

if (revisionsMap != null && !revisionsMap.isEmpty()

&& documentVO.getVer().equals(String.valueOf(revisionsMap.size()))) {

DocumentVO document = revisionsMap.get(documentVO.getVer());

poiForMinorIncrement = poiForMinorIncrement.concat("|" + poiUpdateOnly);

List<String> wip_SharedPOIList = Arrays.asList(poiForMinorIncrement.split("\\|"));

List<String> wip_SharedStatusList = Arrays.asList(statusForMinorIncrement.split("\\|"));

List<String> wip_SharedPOIUpdateOnlyList = Arrays.asList(poiForMinorUpdateOnly.split("\\|"));

List<String> wip_SharedStatusUpdateOnlyList = Arrays.asList(statusForMinorUpdateOnly.split("\\|"));

List<String> sharedPOIListSet1 = Arrays.asList(poiForMajorIncrementSet1.split("\\|"));

List<String> sharedStatusListSet1 = Arrays.asList(statusForMajorIncrementSet1.split("\\|"));

List<String> sharedPOIListSet2 = Arrays.asList(poiForMajorIncrementSet2.split("\\|"));

List<String> sharedStatusListSet2 = Arrays.asList(statusForMajorIncrementSet2.split("\\|"));

List<String> publishedPOIList = Arrays.asList(poiForPublishIncrement.split("\\|"));

List<String> publishedStatusList = Arrays.asList(statusForPublishIncrement.split("\\|"));

String minorRevPattern = "([" + pattern + "][0-9]+.[0-9]+)";

String majorRevPattern = "([" + pattern + "][0-9]+)";

String publishedRevPattern = "([" + patternForPublishedRevision + "][0-9]+)";

String validRevPattern = "([" + pattern + "][0-9]+.[0-9]+)|([" + pattern + "|" + patternForPublishedRevision + "][0-9]+)";

if (wip_SharedPOIUpdateOnlyList.contains(document.getPurposeOfIssue()) && wip_SharedStatusUpdateOnlyList.contains(document.getStatus())) {

// Increment Minor UpdateOnly Set Revision -- START

int publishedRevCount = 0;

boolean revUpdated = false;

boolean majorRevFounded = false;

int currentVer = Integer.parseInt(document.getVer());

int prevVer = currentVer - 1;

for (int index = currentVer - 1; index > 0; index--) {

String ver = String.valueOf(index);

if (revisionsMap.containsKey(ver)) {

String revision = revisionsMap.get(ver).getRevision();

if(revision.matches(validRevPattern)) {

if(revision.matches(minorRevPattern) && (index == prevVer)) {

document.setRevision(revision);

documentsList.add(document);

revUpdated = true;

break;

} else if (revision.matches(publishedRevPattern)) {

publishedRevCount += 1;

} else if (revision.matches(majorRevPattern)) {

revision = incrementRevByVal(revision, publishedRevCount + 1).concat(".01");

document.setRevision(revision);

documentsList.add(document);

majorRevFounded = true;

revUpdated = true;

break;

}

} else {

prevVer--;

}

}

}

if(!majorRevFounded && publishedRevCount == 0 && !revUpdated) {

document.setRevision(pattern.concat(startNumber).concat(".01"));

documentsList.add(document);

} else if (!majorRevFounded && publishedRevCount > 0 && !revUpdated) {

String revision = incrementRevByVal(pattern.concat(startNumber), publishedRevCount).concat(".01");

document.setRevision(revision);

documentsList.add(document);

}

// Increment Minor UpdateOnly Set Revision -- END

} else if (wip_SharedPOIList.contains(document.getPurposeOfIssue()) && wip_SharedStatusList.contains(document.getStatus())) {

// Increment Minor Revision -- START

int publishedRevCount = 0;

boolean majorRevFounded = false;

boolean revUpdated = false;

int currentVer = Integer.parseInt(document.getVer());

int prevVer = currentVer - 1;

for (int index = currentVer - 1; index > 0; index--) {

String ver = String.valueOf(index);

if (revisionsMap.containsKey(ver)) {

String revision = revisionsMap.get(ver).getRevision();

if(revision.matches(validRevPattern)) {

if(revision.matches(minorRevPattern) && (index == prevVer)) {

if (poiUpdateOnly.equals(document.getPurposeOfIssue())) {

document.setRevision(revision);

documentsList.add(document);

} else {

document.setRevision(incrementByOne(revision, true));

documentsList.add(document);

}

revUpdated = true;

break;

} else if (revision.matches(publishedRevPattern)) {

publishedRevCount += 1;

} else if (revision.matches(majorRevPattern)) {

revision = incrementRevByVal(revision, publishedRevCount + 1).concat(".01");

document.setRevision(revision);

documentsList.add(document);

majorRevFounded = true;

revUpdated = true;

break;

}

} else {

prevVer--;

}

}

}

if(!majorRevFounded && publishedRevCount == 0 && !revUpdated) {

document.setRevision(pattern.concat(startNumber).concat(".01"));

documentsList.add(document);

} else if (!majorRevFounded && publishedRevCount > 0 && !revUpdated) {

String revision = incrementRevByVal(pattern.concat(startNumber), publishedRevCount).concat(".01");

document.setRevision(revision);

documentsList.add(document);

}

// Increment Minor Revision -- END

} else if ((sharedPOIListSet1.contains(document.getPurposeOfIssue()) && sharedStatusListSet1.contains(document.getStatus()))

|| (sharedPOIListSet2.contains(document.getPurposeOfIssue()) && sharedStatusListSet2.contains(document.getStatus()))) {

// Increment Major Revision -- START

int publishedRevCount = 0;

boolean majorRevFounded = false;

int currentVer = Integer.parseInt(document.getVer());

for (int index = currentVer - 1; index > 0; index--) {

String ver = String.valueOf(index);

if (revisionsMap.containsKey(ver)) {

String revision = revisionsMap.get(ver).getRevision();

if (revision.matches(publishedRevPattern)) {

publishedRevCount += 1;

} else if (revision.matches(majorRevPattern)) {

majorRevFounded = true;

revision = incrementRevByVal(revision, publishedRevCount + 1);

document.setRevision(revision);

documentsList.add(document);

break;

}

}

}

if(!majorRevFounded && publishedRevCount == 0) {

document.setRevision(pattern.concat(startNumber));

documentsList.add(document);

} else if (!majorRevFounded && publishedRevCount > 0) {

String revision = incrementRevByVal(pattern.concat(startNumber), publishedRevCount);

document.setRevision(revision);

documentsList.add(document);

}

// Increment Major Revision -- END

} else if (publishedPOIList.contains(document.getPurposeOfIssue())

&& publishedStatusList.contains(document.getStatus())) {

// Increment Published Revision -- START

String prePublishedRevision = getPreviousRevBasedOnPOIAndStatus(revisionsMap, document,

publishedPOIList, publishedStatusList, validRevPattern);

if (!"Not Found".equals(prePublishedRevision)) {

document.setRevision(incrementByOne(prePublishedRevision, false));

documentsList.add(document);

} else {

document.setRevision(patternForPublishedRevision.concat(startNumberForPublishedRevision));

documentsList.add(document);

}

// Increment Published Revision -- END

}

}

if (!documentsList.isEmpty())

documentService.updateDocuments(documentsList);

}

// This method provides Rev numbr of revision matched with provided status & POI

public String getPreviousRevBasedOnPOIAndStatus(Map<String, DocumentVO> docMap, DocumentVO document,

List<String> pois, List<String> statuses, String revValidationPattern) {

int currentVer = Integer.parseInt(document.getVer());

String preWipRevision = "Not Found";

for (int index = currentVer - 1; index > 0; index--) {

String ver = String.valueOf(index);

System.out.println(docMap.get(ver).getPurposeOfIssue());

System.out.println(pois);

if (docMap.containsKey(ver) && (pois.contains(docMap.get(ver).getPurposeOfIssue())

&& statuses.contains(docMap.get(ver).getStatus()))) {

String revision = docMap.get(ver).getRevision();

if (revision.matches(revValidationPattern)) {

preWipRevision = revision;

break;

}

}

}

return preWipRevision;

}

// This method will increment major or minor revision

public static String incrementByOne(String number, boolean isUpdateFraction) {

int incrementValue = 1;

String[] value = number.split("[.]");

String numericPattern = "[0-9]+";

String alphaNumericPattern = "[A-Z][0-9]+";

if (value.length == 2) {

if (isUpdateFraction) {

if (value[1].matches(numericPattern)) {

String formater = "%0" + value[1].length() + "d";

value[1] = String.format(formater, Integer.parseInt(value[1]) + incrementValue);

}

} else {

if (value[0].matches(alphaNumericPattern)) {

String firstChar = value[0].substring(0, 1);

String restNumber = value[0].substring(1, value[0].length());

String formater = "%0" + restNumber.length() + "d";

value[0] = firstChar + String.format(formater, Integer.parseInt(restNumber) + incrementValue);

}

}

return value[0].concat(".").concat(value[1]);

} else {

if (value[0].matches(alphaNumericPattern)) {

String firstChar = value[0].substring(0, 1);

String restNumber = value[0].substring(1, value[0].length());

String formater = "%0" + restNumber.length() + "d";

return firstChar + String.format(formater, Integer.parseInt(restNumber) + incrementValue);

}

return "Not Match";

}

}

public static String incrementRevByVal(String number, int incrementValue) {

String alphaNumericPattern = "[A-Z][0-9]+";

if (number.matches(alphaNumericPattern)) {

String firstChar = number.substring(0, 1);

String restNumber = number.substring(1, number.length());

String formater = "%0" + restNumber.length() + "d";

return firstChar + String.format(formater, Integer.parseInt(restNumber) + incrementValue);

}

return "Not Match";

}

Given below are details on how user can edit the script based on project requirements.

Part

Groovy Script

Description

1

def execute() {

//********************* Configurable parameter section *********************************

String pattern = "P";

String startNumber = "01";

String patternForPublishedRevision = "C";

String startNumberForPublishedRevision = "01";

This part helps user to configure the file revision number pattern, by editing the values within double quotes.

1. 'P' indicates the fixed character to be used in the internal revision number.

2. '01' indicates the start number to be included with the fixed character. This will auto increment based on the number of file revisions uploaded with the same document reference.

3. 'C' indicates the fixed character to be used in the external revision number.

4. '01' indicates the start number to be included with the fixed character for published file revisions. This will auto increment based on the number of file revisions uploaded with the same document reference.

2

// Status & POI list to set & update Minor Rev ** // P01.01, P01.02, P01.n...

String poiForMinorIncrement = "S0";

String statusForMinorIncrement = "Work In Progress";

String poiUpdateOnly = "S0 (Update Only)";

String poiForMinorUpdateOnly = "S1|S2";

String statusForMinorUpdateOnly = "Approved as Internal Share,For External Share";

This part helps user to configure the combinations of status and purpose of issue to use the start number that we defined in the point 2 in Part 1 above, by editing the values within double quotes.. This start number will be used as highlighted in the following revision number pattern: P01.01, P01.02,… P01.0n

This start number will be applicable based on the combinations of status and purpose of issue as stated below:

1. 'S0' is the purpose of issue value. You can use either of abbreviation or full text of Purpose of Issue configured in the project.

2. 'Work In Progress' is the status value. You can use either of abbreviation or full text of Status configured in the project.

3. 'S0 (Update Only)' is the purpose of issue value. You can use either of abbreviation or full text of Purpose of Issue configured in the project.

3. 'S1' and 'S2' are the purpose of issue values. Pipe symbol is used as separator to separate the values. You can use either of abbreviation or full text of Purpose of Issues configured in the project.

4. 'Approved as Internal Share' and 'For External Share' are the status values. Comma is used as separator to separate the values. You can use either of abbreviation or full text of Statuses configured in the project.

3

// Status & POI list to set & update Major Rev ** // P01, P02, Pn...

String poiForMajorIncrementSet1 = "S3";

String statusForMajorIncrementSet1 = "Approved as External Shared";

String poiForMajorIncrementSet2 = "P1|P2";

String statusForMajorIncrementSet2 = "For Publishing";

This part helps user to configure the combinations of status and purpose of issue to use the start number that we defined in the point 2 in Part 1 above, by editing the values within double quotes. This start number will be used as highlighted in the following pattern: P01, P02,… P0n

This start number will be applicable based on the combinations of status and purpose of issue as stated below:

1. 'S3' is the purpose of issue value. You can use either of abbreviation or full text of Purpose of Issue configured in the project.

2. 'Approved as External Shared' is the status value. You can use either of abbreviation or full text of Status configured in the project.

3. 'P1' and 'P2' are the purpose of issue values. Pipe symbol is used as separator to separate the values. You can use either of abbreviation or full text of Purpose of Issues configured in the project.

4. 'For Publishing' is the status value. You can use either of abbreviation or full text of Status configured in the project.

4

// Status & POI list to set & update // C01, C02, Cn...

String poiForPublishIncrement = "A1|A2";

String statusForPublishIncrement = "Authorized as Published";

This part helps user to configure the combinations of status and purpose of issue to use the start number that we defined in the point 4 in Part 1 above, by editing the values within double quotes.. This start number will be used as highlighted in the following pattern: C01, C02,… C0n

This start number will be applicable based on the combinations of status and purpose of issue as stated below:

1. 'A1' and 'A2' are the purpose of issue values. Pipe symbol is used as separator to separate the values. You can use either of abbreviation or full text of Purpose of Issues configured in the project.

2. 'Authorized as Published' is the status value. You can use either of abbreviation or full text of Status configured in the project.

Step 2. Once the system task containing groovy script is configured, user can configure a file workflow trigger to run this system task upon 'Publish Documents' / 'Edit Attributes' event in a selected project folder in 'Post' task mode.

Step 3. To understand how the automatic revision numbering will actually work based on the above groovy script configuration, user can upload files into the folder as per workflow trigger configuration.

Below is a table explaining the automatic revision number of the file upon upload, based on the selected combination of file status and purpose of issue mentioned above:

Ver No.

Purpose of Issue

Status

Revision Number

1

S0

Work In Progress

P01.01

2

S0 (Update Only)

Work In Progress

P01.01

3

S1

Approved as Internal Share

P01.02

4

S2

For External Share

P01.03

5

S3

Approved As External Shared

P01

6

P1

For Publishing

P02

7

A1

Authorized as Published

C01

8

A2

Authorized as Published

C02


Check: FAQs


Did this answer your question?