ChangeCalendar/backend/src/main/java/com/nttdata/calender/changes/Change.java

391 lines
20 KiB
Java

package com.nttdata.calender.changes;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Optional;
import java.util.TimeZone;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.bmc.arsys.api.ARException;
import com.bmc.arsys.api.Entry;
import com.bmc.arsys.api.SortInfo;
import com.bmc.arsys.api.Timestamp;
import com.bmc.arsys.api.Value;
import com.nttdata.calender.api.Query;
import com.nttdata.calender.api.RemedyJavaAPI;
import com.nttdata.calender.changes.query.FilterElement;
import com.nttdata.calender.errorhandling.ErrorTypes.NotFoundError;
import com.nttdata.calender.errorhandling.ErrorTypes.ValidationError;
/**
* Class representing the change with all of the change specific attributes.
*/
@Service
public class Change {
private Query queryChange;
private RemedyJavaAPI api;
private final static String formName = "ASF:WI_TAS_Paket";
/**
* Constructor for the {@link Change} class which gets autowired with the
* {@link RemedyJavaAPI} api.
*
* @param api the RemedyJavaAPI instance to be injected
*/
@Autowired
public Change(RemedyJavaAPI api) {
this.api = api;
this.queryChange = new Query.QueryBuilder(formName)
.addFieldId("ChangeNr", 1000000182)
.addFieldId("SupportGroup", 1000000015)
.addFieldId("State", 7)
.addFieldId("ResourceName", 1000000000)
.addFieldId("D1", 1000000349)
.addFieldId("D2", 1000000350)
.addFieldId("D3", 666000350)
.addFieldId("D4", 1000000364)
.addFieldId("StatusReason", 1000000150)
.addFieldId("ApprovalStatus", 1000003264)
.addFieldId("CoordinatorSg", 1000003229)
.addFieldId("CoordinatorSgId", 1000003234)
.addFieldId("ChangeCoordinator", 1000003230)
.addFieldId("SupportGroupId", 1000000079)
.addFieldId("ProviderCluster", 610020002)
.addFieldId("ChangeImplementer", 610023230)
.addFieldId("ChangeImplementerLogin", 610023231)
.addFieldId("ChangeImplementerPersonId", 610023232)
.addFieldId("PackageType", 670031016)
.addFieldId("Contract", 670031002)
.addFieldId("PlanTimeHours", 666000009)
.addFieldId("PlanTimeMinutes", 666000010)
.build();
}
/**
* Retrieves entries from the form using the given qualification. With the
* returned entry set,
* prints out the ID of each entry and the contents in its shortDescription
* field.
*
* @param request the defined qualifier for specific selection
* @return a List of Change for every entry found
* @throws ARException if an error occurs during the retrieval process
* @throws NotFoundError if no user is found with the specified login ID
* @throws ValidationError if there is an invalid filter or qualification
*/
public ChangeResponse get(ChangeRequest request) throws ARException, NotFoundError, ValidationError {
api.impersonateUser("ext_StanzPa");
var peopleFullName = processPeopleInfo(request);
var filter = request.getFilter();
var qualifier = filter.constructQualifier(queryChange, api);
SortInfo sort = request.constructSortInfo(queryChange);
var entries = api.queryFieldsById(qualifier, this.queryChange.getFieldIds(),
this.queryChange.getFormName(),
sort, request.getSliceStart(),
request.getSliceEnd());
var entriesSize = api.getFormSize(qualifier, this.queryChange.getFormName());
var changes = new ArrayList<ChangeItem>();
for (var entry : entries) {
var change = new ChangeItem(entry.getEntryId());
change.setChangeNr(getValueStringByID(entry, "ChangeNr"));
change.setSupportGroup(getValueStringByID(entry, "SupportGroup"));
change.setState(Optional.ofNullable(getValue(entry, "State"))
.map(Value::getIntValue)
.orElse(-1));
change.setResourceName(getValueStringByID(entry, "ResourceName"));
change.setD1(timestampToDateById(entry, "D1"));
change.setD2(timestampToDateById(entry, "D2"));
change.setD3(timestampToDateById(entry, "D3"));
change.setD4(timestampToDateById(entry, "D4"));
change.setStatusReason(getValueStringByID(entry, "StatusReason"));
change.setApprovalStatus(getValueStringByID(entry, "ApprovalStatus"));
change.setCoordinatorSg(getValueStringByID(entry, "CoordinatorSg"));
change.setCoordinatorSgId(getValueStringByID(entry, "CoordinatorSgId"));
change.setSupportGroupId(getValueStringByID(entry, "SupportGroupId"));
change.setProviderCluster(getValueStringByID(entry, "ProviderCluster"));
change.setChangeImplementer(getValueStringByID(entry, "ChangeImplementer"));
change.setChangeImplementerLogin(getValueStringByID(entry, "ChangeImplementerLogin"));
change.setChangeImplementerPersonId(getValueStringByID(entry, "ChangeImplementerPersonId"));
change.setPackageType(getValueStringByID(entry, "PackageType"));
change.setContract(getValueStringByID(entry, "Contract"));
change.setImplementerEdit(
Optional.ofNullable(entry.get(queryChange.getFieldId("ChangeCoordinator")))
.map(Object::toString)
.filter(peopleFullName::equals)
.isPresent());
/*
* var state = getValue(entry, "State").getIntValue();
* var inApproval = inApprovalList(api.getUser(), getValueStringByID(entry,
* "ChangeNr"));
*
* change.setFlagPermit(flagPermit(state));
* change.setFlagApprove(flagApproval(inApproval, state));
* change.setFlagReject(flagApproval(inApproval, state));
* change.setFlagCancel(flagCancel(getValueStringByID(entry, "SupportGroupId"),
* state));
*/
// change.setFlagPermit(flagPermit(state));
// change.setFlagApprove(flagApproval(inApproval, state));
// change.setFlagReject(flagApproval(inApproval, state));
// change.setFlagCancel(flagCancel(getValueStringByID(entry, "SupportGroupId"),
// state));
change.setPackageName(queryPackageName(getValueStringByID(entry, "PackageType").toString()));
var ptMinutes = getValueStringByID(entry, "PlanTimeMinutes").isEmpty() ? "00"
: getValueStringByID(entry, "PlanTimeMinutes");
var ptHours = getValueStringByID(entry, "PlanTimeHours").isEmpty() ? "00"
: getValueStringByID(entry, "PlanTimeHours");
change.setPlanTime(convertPlanTime(ptHours, ptMinutes));
change.setPackageName(queryPackageName(getValueStringByID(entry, "PackageType").toString()));
changes.add(change);
}
api.freeImpersonatedUser();
return new ChangeResponse(entriesSize, changes);
}
/**
* Processes the people information based on the provided change request.
* Returns the full name of the impersonated user after querying for the support
* group.
*
* @param request the change request object
* @return the full name of the impersonated user
* @throws ARException if an AR exception occurs
* @throws NotFoundError if no user or support groups are found with the
* provided login ID
*/
private String processPeopleInfo(ChangeRequest request) throws ARException, NotFoundError {
// Queries for SupportGroup of impersonated User
var queryPerson = new Query.QueryBuilder("CTM:Support Group Association")
.addFieldId("FullName", 1000000017)
.addFieldId("SupportGroupId", 1000000079)
.build();
var peopleInfos = api.queryFieldsById("\'Login ID\' = \"" + api.getUser() + "\"",
queryPerson.getFieldIds(),
queryPerson.getFormName(), null, 0, 0);
if (peopleInfos.isEmpty()) {
throw new NotFoundError("No user found with this loginId");
}
// constructs set of supportGroups and full name of impersonated User
String[] peopleSupportGroup = peopleInfos.stream()
.map(entry -> entry.get(queryPerson.getFieldId("SupportGroupId")).toString())
.toArray(String[]::new);
if (peopleSupportGroup.length <= 0) {
throw new NotFoundError("No supportGroups associated to the loginId ");
}
request.addFilter(
new FilterElement("SupportGroupId", "equals", peopleSupportGroup));
return peopleInfos.get(0).get(queryPerson.getFieldId("FullName")).toString();
}
/**
* Converts the planned time which is passed in hours and minutes to total hours
*
* @param hours the hours as a String
* @param minutes the minutes as a String
* @return the hours and minutes as total hours
* @throws ARException
*/
public double convertPlanTime(String hours, String minutes) throws ARException {
double totalHours = Integer.valueOf(hours) + (Integer.valueOf(minutes) / 60.0);
return totalHours;
}
// #region approval flags
// /**
// * Determines if the change item can be approved based on the approval status
// * and the current state.
// *
// * @param approval The flag indicating whether the change item has been
// * approved.
// * @param state The current state of the change item.
// * @return {@code true} if the change item can be approved, {@code false}
// * otherwise.
// */
// public boolean flagApproval(boolean approval, int state) {
// boolean approvableState = (state == 1 || state == 10);
// return approval && approvableState;
// }
// /**
// * Determines if the change item can be canceled based on the support group ID
// * and the current state.
// *
// * @param supportGroupId The ID of the support group associated with the
// change item
// * @param state The current state of the change item
// * @return {@code true} if the change item can be canceled, {@code false}
// otherwise.
// * @throws ARException if an error occurs during the operation
// */
// public boolean flagCancel(String supportGroupId, int state) throws
// ARException {
// var queryRoles = new
// Query.QueryBuilder("CTM:SupportGroupFuncRoleLookUp").addFieldId("Role",
// 1000000014)
// .build();
// var role = api.queryFieldsById("\'Support Group ID\' = \"" + supportGroupId +
// "\"",
// queryRoles.getFieldIds(), queryRoles.getFormName(), null, 0, 0)
// .get(0).get(queryRoles.getFieldId("Role")).toString();
// boolean approvableState = state == 1;
// boolean isChangeManager = role.equals("Change Manager");
// return approvableState && isChangeManager;
// }
// /**
// * Determines if the change item has a permit based on the current state.
// *
// * @param state The current state of the change item.
// * @return {@code true} if the change item has a permit, {@code false}
// otherwise.
// */
// public boolean flagPermit(int state) {
// return state == 0;
// }
// /**
// * Checks if the logged in user is in the approval list for the specified
// change item.
// *
// * @param user The username of the user to check
// * @param changeNr The change number of the change item
// * @return {@code true} if the user is in the approval list, {@code false}
// otherwise.
// * @throws ARException if an error occurs during the operation
// */
// public boolean inApprovalList(String user, String changeNr) throws
// ARException {
// var queryApprovalList = new
// Query.QueryBuilder("ASF:OverviewConsole_TicketsJoinAPDetailSignature")
// .addFieldId("Approvers", 13207).build();
// var approversOI = api.queryFieldsById("\'Ticketnumber\' = \"" + changeNr +
// "\"",
// queryApprovalList.getFieldIds(), queryApprovalList.getFormName(), null, 0,
// 0);
// var approvers = approversOI.isEmpty() ? null
// :
// approversOI.get(0).get(queryApprovalList.getFieldId("Approvers")).toString();
// return approvers != null ? approvers.contains(user) : false;
// }
// #endregion
/**
* Queries and retrieves the package name based on the provided package type.
* Returns the package name as a string.
*
* @param packageType the type of the package
* @return the package name
* @throws ARException if an AR exception occurs
*/
private String queryPackageName(String packageType) throws ARException {
var queryPackage = new Query.QueryBuilder("CTR:GenericContractJoinCFG_Package")
.addFieldId("PackageName", 200000020).build();
var packageName = api
.queryFieldsById("\'InstanceId_Package\' = \"" + packageType + "\"",
queryPackage.getFieldIds(), queryPackage.getFormName(), null, 0, 0)
.get(0);
return packageName.get(queryPackage.getFieldId("PackageName")).toString();
}
/**
* Returns the {@link Value} of an entry based on the provided description.
*
* @param entry the {@link Entry} from which a value will be retrieved
* @param description the name of the field from which the value should be
* retrieved
* @return the value of the entry
*/
private Value getValue(Entry entry, String description) {
return entry.get(this.queryChange.getFieldId(description));
}
/**
* Converts a {@link Timestamp} to a {@link Date} format or returns null if the
* timestamp is null.
*
* @param entry the {@link Entry} containing the timestamp value
* @param description the description of the field containing the timestamp
* value
* @return the converted {@link Date} or null if the timestamp is null
*/
private Date timestampToDateById(Entry entry, String description) {
return Optional.ofNullable(getValue(entry, description))
.map(Value::getValue)
.map(Timestamp.class::cast)
.map(Timestamp::toDate)
.orElse(null);
}
/**
* Remaps a {@link Value} to a String if possible, or returns null.
*
* @param entry the {@link Entry} from which the value should be retrieved
* @param description the description of the field containing the value
* @return the value as a {@link String} or null
*/
private String getValueStringByID(Entry entry, String description) {
return Optional.ofNullable(getValue(entry, description))
.map(Value::toString)
.orElse("");
}
/**
* Updates the timestamp of a change entry or modifies the short description
* field on the specified entry.
* Extracts data from the request object.
* Builds the query to update the d2 field.
* Modifies the entry on one of two forms according to the state.
*
* @param request the object containing the ID of the change entry and the new
* timestamp
* @throws ARException if an error occurs during the modification process
* @throws ValidationError
*/
public void modifyTimestamp(ChangeUpdateRequest request) throws ARException, ValidationError {
String entryId = request.getResourceId();
String d2 = request.getD2();
int state = request.getState();
String changeNr = request.getChangeNr();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSS'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
try {
Timestamp ts = new Timestamp(sdf.parse(d2));
if (state == 0) {
Query query = new Query.QueryBuilder("ASF:WI_TAS_Paket")
.addFieldValue("d2", 1000000350, new Value(ts)).build();
api.modifyEntry(entryId, query);
} else {
Query queryInfrastructureChange = new Query.QueryBuilder("CHG:Infrastructure Change")
.addFieldValue("d2", 1000000350, new Value(ts)).build();
var change = api.queryFieldsById("\'Infrastructure Change ID\' = \"" + changeNr + "\"",
queryInfrastructureChange.getFieldIds(),
queryInfrastructureChange.getFormName(), null, 0, 0);
api.modifyEntry(change.get(0).getEntryId(), queryInfrastructureChange);
}
} catch (ParseException e) {
throw new ValidationError("Incorrect dateformat in request");
}
}
}