Skip to content

Commit

Permalink
Add support for Role Codes (#791)
Browse files Browse the repository at this point in the history
  • Loading branch information
joniles authored Dec 13, 2024
1 parent 771a403 commit 282bdf8
Show file tree
Hide file tree
Showing 8 changed files with 371 additions and 23 deletions.
1 change: 1 addition & 0 deletions src/changes/changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<release date="unreleased" version="13.8.0">
<action dev="joniles" type="update">Added support for reading and writing Project Codes for Primavera P6 schedules.</action>
<action dev="joniles" type="update">Added support for reading and writing Resource Codes for Primavera P6 schedules.</action>
<action dev="joniles" type="update">Added support for reading and writing Role Codes for Primavera P6 schedules.</action>
<action dev="joniles" type="update">When writing PMXML files, improve handling of P6 schedules where activity code sequence numbers are missing.</action>
<action dev="joniles" type="update">Added an *experimental* feature to `MSPDIWriter` to allow the writer to generate timephased data when none is present. Disabled by default, call the `setGenerateMissingTimephasedData` and pass `true` to enable.</action>
<action dev="joniles" type="update">To improve consistency, the methods `Task.getPrimaryResourceID()` and `Task.setPrimaryResourceID()` have been marked as deprecated. Use the new `Task.getPrimaryResourceUniqueID()` and `Task.setPrimaryResourceUniqueID()` methods instead.</action>
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/net/sf/mpxj/explorer/ProjectTreeController.java
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,14 @@ public void loadFile(File file, ProjectFile projectFile)
projectNode.add(projectCodesFolder);
addCodes(projectCodesFolder, m_projectFile.getProjectCodes());

MpxjTreeNode resourceCodesFolder = new MpxjTreeNode("Resource Codes");
projectNode.add(resourceCodesFolder);
addCodes(resourceCodesFolder, m_projectFile.getResourceCodes());

MpxjTreeNode roleCodesFolder = new MpxjTreeNode("Role Codes");
projectNode.add(roleCodesFolder);
addCodes(roleCodesFolder, m_projectFile.getRoleCodes());

m_model.setRoot(projectNode);
}

Expand Down
68 changes: 55 additions & 13 deletions src/main/java/net/sf/mpxj/primavera/PrimaveraDatabaseReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,13 @@ private ProjectFile read(ProjectFileSharedData shared) throws MPXJException
processUdfDefinitions();
processProjectCodeDefinitions();
processResourceCodeDefinitions();
processRoleCodeDefinitions();
processActivityCodeDefinitions();
}

processActivityCodeAssignments();
processResourceCodeAssignments();
processRoleCodeAssignments();
processUdfValues();
processCalendars();
processResources();
Expand Down Expand Up @@ -328,47 +330,87 @@ private void processNotebookTopics() throws SQLException
*/
private void processActivityCodeDefinitions() throws SQLException
{
List<Row> types = getRows("select * from " + m_schema + "actvtype where actv_code_type_id in (select distinct actv_code_type_id from taskactv where proj_id=?)", m_projectID);
List<Row> typeValues = getRows("select * from " + m_schema + "actvcode where actv_code_id in (select distinct actv_code_id from taskactv where proj_id=?)", m_projectID);
m_reader.processActivityCodeDefinitions(types, typeValues);
if (m_tableNames.contains("ACTVTYPE") && m_tableNames.contains("ACTVCODE"))
{
List<Row> types = getRows("select * from " + m_schema + "actvtype where actv_code_type_id in (select distinct actv_code_type_id from taskactv where proj_id=?)", m_projectID);
List<Row> typeValues = getRows("select * from " + m_schema + "actvcode where actv_code_id in (select distinct actv_code_id from taskactv where proj_id=?)", m_projectID);
m_reader.processActivityCodeDefinitions(types, typeValues);
}
}

/**
* Process project code definitions.
*/
private void processProjectCodeDefinitions() throws SQLException
{
List<Row> types = getRows("select * from " + m_schema + "pcattype where proj_catg_type_id in (select distinct proj_catg_type_id from projpcat where proj_id=?)", m_projectID);
List<Row> typeValues = getRows("select * from " + m_schema + "pcatval where proj_catg_id in (select distinct proj_catg_id from projpcat where proj_id=?)", m_projectID);
m_reader.processProjectCodeDefinitions(types, typeValues);
if (m_tableNames.contains("PCATTYPE") && m_tableNames.contains("PCATVAL"))
{
List<Row> types = getRows("select * from " + m_schema + "pcattype where proj_catg_type_id in (select distinct proj_catg_type_id from projpcat where proj_id=?)", m_projectID);
List<Row> typeValues = getRows("select * from " + m_schema + "pcatval where proj_catg_id in (select distinct proj_catg_id from projpcat where proj_id=?)", m_projectID);
m_reader.processProjectCodeDefinitions(types, typeValues);
}
}

/**
* Process resource code definitions.
*/
private void processResourceCodeDefinitions() throws SQLException
{
List<Row> types = getRows("select * from " + m_schema + "rcattype where rsrc_catg_type_id in (select distinct rsrc_catg_type_id from rsrcrcat where rsrc_id in (select distinct rsrc_id from " + m_schema + "taskrsrc t where proj_id=? and delete_date is null))", m_projectID);
List<Row> typeValues = getRows("select * from " + m_schema + "rcatval where rsrc_catg_id in (select distinct rsrc_catg_id from rsrcrcat where rsrc_id in (select distinct rsrc_id from " + m_schema + "taskrsrc t where proj_id=? and delete_date is null))", m_projectID);
m_reader.processResourceCodeDefinitions(types, typeValues);
if (m_tableNames.contains("RCATTYPE") && m_tableNames.contains("RCATVAL"))
{
List<Row> types = getRows("select * from " + m_schema + "rcattype where rsrc_catg_type_id in (select distinct rsrc_catg_type_id from rsrcrcat where rsrc_id in (select distinct rsrc_id from " + m_schema + "taskrsrc t where proj_id=? and delete_date is null))", m_projectID);
List<Row> typeValues = getRows("select * from " + m_schema + "rcatval where rsrc_catg_id in (select distinct rsrc_catg_id from rsrcrcat where rsrc_id in (select distinct rsrc_id from " + m_schema + "taskrsrc t where proj_id=? and delete_date is null))", m_projectID);
m_reader.processResourceCodeDefinitions(types, typeValues);
}
}

/**
* Process role code definitions.
*/
private void processRoleCodeDefinitions() throws SQLException
{
if (m_tableNames.contains("ROLECATTYPE") && m_tableNames.contains("ROLECATVAL"))
{
List<Row> types = getRows("select * from " + m_schema + "rolecattype where role_catg_type_id in (select distinct role_catg_type_id from rolercat where role_id in (select distinct role_id from " + m_schema + "rsrcrole where delete_date is null and rsrc_id in (select rsrc_id from " + m_schema + "taskrsrc t where proj_id=? and delete_date is null)))", m_projectID);
List<Row> typeValues = getRows("select * from " + m_schema + "rolecatval where role_catg_id in (select distinct role_catg_id from rolercat where role_id in (select distinct role_id from " + m_schema + "rsrcrole where delete_date is null and rsrc_id in (select rsrc_id from " + m_schema + "taskrsrc t where proj_id=? and delete_date is null)))", m_projectID);
m_reader.processRoleCodeDefinitions(types, typeValues);
}
}

/**
* Process activity code assignments.
*/
private void processActivityCodeAssignments() throws SQLException
{
List<Row> assignments = getRows("select * from " + m_schema + "taskactv where proj_id=?", m_projectID);
m_reader.processActivityCodeAssignments(assignments);
if (m_tableNames.contains("TASKACTV"))
{
List<Row> assignments = getRows("select * from " + m_schema + "taskactv where proj_id=?", m_projectID);
m_reader.processActivityCodeAssignments(assignments);
}
}

/**
* Process resource code assignments.
*/
private void processResourceCodeAssignments() throws SQLException
{
List<Row> assignments = getRows("select * from " + m_schema + "rsrcrcat where rsrc_id in (select distinct rsrc_id from " + m_schema + "taskrsrc t where proj_id=? and delete_date is null)", m_projectID);
m_reader.processResourceCodeAssignments(assignments);
if (m_tableNames.contains("RSRCRCAT"))
{
List<Row> assignments = getRows("select * from " + m_schema + "rsrcrcat where rsrc_id in (select distinct rsrc_id from " + m_schema + "taskrsrc t where proj_id=? and delete_date is null)", m_projectID);
m_reader.processResourceCodeAssignments(assignments);
}
}

/**
* Process role code assignments.
*/
private void processRoleCodeAssignments() throws SQLException
{
if (m_tableNames.contains("ROLERCAT"))
{
List<Row> assignments = getRows("select * from " + m_schema + "rolercat where role_id in (select distinct role_id from " + m_schema + "rsrcrole where delete_date is null and rsrc_id in (select distinct rsrc_id from " + m_schema + "taskrsrc t where proj_id=? and delete_date is null)", m_projectID);
m_reader.processRoleCodeAssignments(assignments);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1448,7 +1448,7 @@ private void processRoles(APIBusinessObjects apibo)
resource.setNotesObject(getHtmlNote(role.getResponsibilities()));
resource.setSequenceNumber(role.getSequenceNumber());

//processRoleCodeAssignments(resource, role.getCode());
processRoleCodeAssignments(resource, role.getCode());
}
}

Expand Down
62 changes: 62 additions & 0 deletions src/main/java/net/sf/mpxj/primavera/PrimaveraPMProjectWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
import net.sf.mpxj.ProjectCodeValue;
import net.sf.mpxj.ResourceCode;
import net.sf.mpxj.ResourceCodeValue;
import net.sf.mpxj.RoleCode;
import net.sf.mpxj.RoleCodeValue;
import net.sf.mpxj.Shift;
import net.sf.mpxj.ShiftPeriod;
import net.sf.mpxj.SkillLevel;
Expand Down Expand Up @@ -129,6 +131,8 @@
import net.sf.mpxj.primavera.schema.ResourceRateType;
import net.sf.mpxj.primavera.schema.ResourceRoleType;
import net.sf.mpxj.primavera.schema.ResourceType;
import net.sf.mpxj.primavera.schema.RoleCodeType;
import net.sf.mpxj.primavera.schema.RoleCodeTypeType;
import net.sf.mpxj.primavera.schema.RoleRateType;
import net.sf.mpxj.primavera.schema.RoleType;
import net.sf.mpxj.primavera.schema.ScheduleOptionsType;
Expand Down Expand Up @@ -215,6 +219,7 @@ private void write(boolean baseline)
writeUnitsOfMeasure();
writeProjectCodeDefinitions();
writeResourceCodeDefinitions();
writeRoleCodeDefinitions();
writeProjectCodeAssignments(project.getCode());
writeActivityCodeDefinitions(project.getActivityCodeType(), project.getActivityCode());
writeCalendars(project.getCalendar());
Expand Down Expand Up @@ -948,6 +953,8 @@ private void writeRole(Resource mpxj)
xml.setCalculateCostFromUnits(Boolean.valueOf(mpxj.getCalculateCostsFromUnits()));
xml.setResponsibilities(getNotes(mpxj.getNotesObject()));
xml.setSequenceNumber(mpxj.getSequenceNumber());

writeRoleCodeAssignments(mpxj, xml.getCode());
}

/**
Expand Down Expand Up @@ -1894,6 +1901,36 @@ private void writeResourceCodeDefinitions()
}
}

/**
* Write role code definitions.
*/
private void writeRoleCodeDefinitions()
{
for (RoleCode code : m_projectFile.getRoleCodes())
{
RoleCodeTypeType xmlCode = m_factory.createRoleCodeTypeType();
m_apibo.getRoleCodeType().add(xmlCode);
xmlCode.setObjectId(code.getUniqueID());
xmlCode.setName(code.getName());
xmlCode.setSequenceNumber(code.getSequenceNumber());
xmlCode.setIsSecureCode(Boolean.valueOf(code.getSecure()));
xmlCode.setLength(code.getMaxLength());

for (RoleCodeValue value : code.getValues())
{
RoleCodeType xmlValue = m_factory.createRoleCodeType();
m_apibo.getRoleCode().add(xmlValue);

xmlValue.setObjectId(value.getUniqueID());
xmlValue.setCodeTypeObjectId(code.getUniqueID());
xmlValue.setCodeValue(value.getName());
xmlValue.setDescription(value.getDescription());
xmlValue.setParentObjectId(value.getParentValueUniqueID());
xmlValue.setSequenceNumber(value.getSequenceNumber());
}
}
}

/**
* Write project code assignments.
*
Expand Down Expand Up @@ -1929,6 +1966,17 @@ private void writeResourceCodeAssignments(Resource resource, List<CodeAssignment
resource.getResourceCodeValues().values().stream().sorted(Comparator.comparing(ResourceCodeValue::getUniqueID)).forEach(v -> writeResourceCodeAssignment(assignments, v));
}

/**
* Write role code assignments.
*
* @param role parent role
* @param assignments role code assignments
*/
private void writeRoleCodeAssignments(Resource role, List<CodeAssignmentType> assignments)
{
role.getRoleCodeValues().values().stream().sorted(Comparator.comparing(RoleCodeValue::getUniqueID)).forEach(v -> writeRoleCodeAssignment(assignments, v));
}

/**
* Write a resource code assignment.
*
Expand All @@ -1943,6 +1991,20 @@ private void writeResourceCodeAssignment(List<CodeAssignmentType> assignments, R
xml.setValueObjectId(NumberHelper.getInt(value.getUniqueID()));
}

/**
* Write a role code assignment.
*
* @param assignments role code assignments
* @param value role code value
*/
private void writeRoleCodeAssignment(List<CodeAssignmentType> assignments, RoleCodeValue value)
{
CodeAssignmentType xml = m_factory.createCodeAssignmentType();
assignments.add(xml);
xml.setTypeObjectId(NumberHelper.getInt(value.getRoleCodeUniqueID()));
xml.setValueObjectId(NumberHelper.getInt(value.getUniqueID()));
}

/**
* Write an activity code value.
*
Expand Down
92 changes: 92 additions & 0 deletions src/main/java/net/sf/mpxj/primavera/PrimaveraReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
import net.sf.mpxj.ResourceCode;
import net.sf.mpxj.ResourceCodeContainer;
import net.sf.mpxj.ResourceCodeValue;
import net.sf.mpxj.RoleCode;
import net.sf.mpxj.RoleCodeContainer;
import net.sf.mpxj.RoleCodeValue;
import net.sf.mpxj.SchedulingProgressedActivities;
import net.sf.mpxj.Shift;
import net.sf.mpxj.ShiftContainer;
Expand Down Expand Up @@ -512,6 +515,48 @@ public void processResourceCodeDefinitions(List<Row> types, List<Row> typeValues
}
}

/**
* Read role code definitions.
*
* @param types role code type data
* @param typeValues role code value data
*/
public void processRoleCodeDefinitions(List<Row> types, List<Row> typeValues)
{
RoleCodeContainer container = m_project.getRoleCodes();
Map<Integer, RoleCode> map = new HashMap<>();

for (Row row : types)
{
RoleCode code = new RoleCode.Builder(m_project)
.uniqueID(row.getInteger("role_catg_type_id"))
.sequenceNumber(row.getInteger("seq_num"))
.name(row.getString("role_catg_type"))
.maxLength(row.getInteger("role_catg_short_len"))
.build();
container.add(code);
map.put(code.getUniqueID(), code);
}

typeValues = HierarchyHelper.sortHierarchy(typeValues, v -> v.getInteger("role_catg_id"), v -> v.getInteger("parent_role_catg_id"));
for (Row row : typeValues)
{
RoleCode code = map.get(row.getInteger("role_catg_type_id"));
if (code != null)
{
RoleCodeValue value = new RoleCodeValue.Builder(m_project)
.roleCode(code)
.uniqueID(row.getInteger("role_catg_id"))
.sequenceNumber(row.getInteger("seq_num"))
.name(row.getString("role_catg_short_name"))
.description(row.getString("role_catg_name"))
.parentValue(code.getValueByUniqueID(row.getInteger("parent_role_catg_id")))
.build();
code.addValue(value);
}
}
}

/**
* Process activity code assignments.
*
Expand Down Expand Up @@ -542,6 +587,21 @@ public void processResourceCodeAssignments(List<Row> assignments)
}
}

/**
* Process role code assignments.
*
* @param assignments role code assignments
*/
public void processRoleCodeAssignments(List<Row> assignments)
{
for (Row row : assignments)
{
Integer resourceID = row.getInteger("role_id");
List<Row> list = m_roleCodeAssignments.computeIfAbsent(resourceID, k -> new ArrayList<>());
list.add(row);
}
}

/**
* Process User Defined Field (UDF) definitions.
*
Expand Down Expand Up @@ -915,6 +975,8 @@ public void processRoles(List<Row> rows)
resource.setRole(true);
resource.setUniqueID(m_roleClashMap.addID(resource.getUniqueID()));
resource.setNotesObject(getNotes(resource.getNotes()));

populateRoleCodeValues(resource);
}
}

Expand Down Expand Up @@ -1446,6 +1508,35 @@ private void populateResourceCodeValues(Resource resource)
}
}

/**
* Read details of any role codes assigned to this role.
*
* @param role parent role
*/
private void populateRoleCodeValues(Resource role)
{
List<Row> list = m_roleCodeAssignments.get(role.getUniqueID());
if (list == null)
{
return;
}

for (Row row : list)
{
RoleCode code = m_project.getRoleCodes().getByUniqueID(row.getInteger("role_catg_type_id"));
if (code == null)
{
continue;
}

RoleCodeValue value = code.getValueByUniqueID(row.getInteger("role_catg_id"));
if (value != null)
{
role.addRoleCodeValue(value);
}
}
}

/**
* Adds a user defined field value to a task.
*
Expand Down Expand Up @@ -2637,6 +2728,7 @@ public static Map<FieldType, String> getDefaultAssignmentFieldMap()
private final Map<String, Map<Integer, List<Row>>> m_udfValues = new HashMap<>();
private final Map<Integer, List<Row>> m_activityCodeAssignments = new HashMap<>();
private final Map<Integer, List<Row>> m_resourceCodeAssignments = new HashMap<>();
private final Map<Integer, List<Row>> m_roleCodeAssignments = new HashMap<>();

private final ObjectSequence m_relationObjectID;

Expand Down
Loading

0 comments on commit 282bdf8

Please sign in to comment.