Verwenden von Projektplanungs-APIs zur Durchführung von Vorgängen mit Entitäten der Zeitplanung
Gilt für: Project Operations für Szenarien basierend auf vorrätigen/nicht vorrätigen Ressourcen, Lite-Bereitstellung – Abwicklung der Proforma-Rechnungsstellung.
Planungsentitäten
Projektzeitplan-APIs bieten die Möglichkeit, Vorgänge zum Erstellen, Aktualisieren und Löschen mit Terminplan-Entitäten auszuführen. Diese Entitäten werden über das Planungsmodul in Project für das Web verwaltet. Erstellen, Aktualisieren und Löschen von Vorgängen mit Planungsentitäten wurden in früheren Version von Dynamics 365 Project Operations eingeschränkt.
Die folgende Tabelle enthält eine vollständige Liste der Projektzeitplan-Entitäten.
Entitätsname | Logischer Entitätsname |
---|---|
Project | msdyn_project |
Projektaufgabe | msdyn_projecttask |
Abhängigkeit der Projektaufgaben | msdyn_projecttaskdependency |
Ressourcenzuweisung | msdyn_resourceassignment |
Projekt-Bucket | msdyn_projectbucket |
Projektteammitglied | msdyn_projectteam |
Projektprüflisten | msdyn_projectchecklist |
Projektbeschriftung | msdyn_projectlabel |
Zu beschriftende Projektaufgabe | msdyn_projecttasktolabel |
Projektsprint | msdyn_projectsprint |
OperationSet
OperationSet ist ein Arbeitseinheitsmuster, das verwendet werden kann, wenn innerhalb einer Transaktion mehrere zeitplanbezogene Anforderungen verarbeitet werden müssen.
Projektzeitplan-APIs
Im Folgenden finden Sie eine Liste der aktuellen Projektzeitplan-APIs.
API | Beschreibung des Dataflows |
---|---|
msdyn_CreateProjectV1 | Diese API wird verwendet, um ein Projekt zu erstellen. Das Projekt und der Standardprojekt-Bucket werden sofort erstellt. Die Projekterstellung kann auch durch Hinzufügen einer Zeile zur Projekttabelle mithilfe von Standard-Dataverse-APIs erfolgen. Dieser Vorgang erstellt kein Standard-Bucket für das Projekt, bietet aber möglicherweise eine bessere Leistung. |
msdyn_CreateTeamMemberV1 | Diese API wird verwendet, um ein Teammitglied zu erstellen. Der Teammitgliedsdatensatz wird sofort erstellt. Die Teammitgliedererstellung kann auch durch Hinzufügen einer Zeile zur Projektteammitgliedertabelle mithilfe von Standard-Dataverse-APIs erfolgen. |
msdyn_CreateOperationSetV1 | Mit dieser API können mehrere Anforderungen geplant werden, die innerhalb einer Transaktion ausgeführt werden müssen. |
msdyn_PssCreateV1 | Diese API wird verwendet, um eine Entität zu erstellen. Die Entität kann eine der Projektplanungs-Entitäten sein, die den Vorgang des Erstellens unterstützen. |
msdyn_PssCreateV2 | Diese API wird verwendet, um eine Entität zu erstellen. Es funktioniert wie msdyn_PssCreateV1, aber mehrere Entitäten können in einer Aktion erstellt werden. |
msdyn_PssUpdateV1 | Diese API wird verwendet, um eine Entität zu aktualisieren. Die Entität kann eine beliebige Projektplanungs-Entität sein, die den Vorgang „Aktualisieren“ unterstützt. |
msdyn_PssUpdateV2 | Diese API wird verwendet, um Entitäten zu aktualisieren. Es funktioniert wie msdyn_PssUpdateV1, aber mehrere Entitäten können in einer Aktion aktualisiert werden. |
msdyn_PssDeleteV1 | Diese API wird verwendet, um eine Entität zu löschen. Die Entität kann eine beliebige Projektplanungs-Entität sein, die den Vorgang „Löschen“ unterstützt. |
msdyn_PssDeleteV2 | Diese API wird verwendet, um Entitäten zu löschen. Es funktioniert wie msdyn_PssDeleteV1, aber mehrere Entitäten können in einer Aktion gelöscht werden. |
msdyn_ExecuteOperationSetV1 | Diese API wird verwendet, um alle Operationen innerhalb des angegebenen Operationssatzes auszuführen. |
msdyn_PssUpdateResourceAssignmentV1 | Diese API wird verwendet, um eine geplante Arbeitskontur der Ressourcenzuweisung zu aktualisieren. |
Verwenden von Projektzeitplan-APIs mit OperationSet
Da Datensätze sowohl mit CreateProjectV1 als auch CreateTeamMemberV1 sofort erstellt werden, können diese APIs nicht direkt in OperationSet verwendet werden. Sie können sie jedoch verwenden, um die erforderlichen Datensätze zu erstellen, ein Operationsset zu erstellen und dann die vorab erstellten Datensätze im Operationsset zu verwenden.
Unterstützte Vorgänge
Planungsentität | Erstellen | Aktualisieren | Delete | Wichtige Überlegungen |
---|---|---|---|---|
Projektaufgabe | Ja | Ja | Ja | Die Felder Fortschritt, EffortCompleted und EffortRemaining können in Project for the Web bearbeitet werden, aber sie können nicht in Project Operations bearbeitet werden. |
Abhängigkeit der Projektaufgaben | Ja | Nein | Ja | Abhängigkeitsdatensätze für Projektaufgaben werden nicht aktualisiert. Stattdessen kann ein alter Datensatz gelöscht und ein neuer Datensatz erstellt werden. |
Ressourcenzuweisung | Ja | Ja* | Ja | Vorgänge mit den folgenden Feldern werden nicht unterstützt: BookableResourceID, Aufwand, EffortCompleted, EffortRemaining und PlannedWork. |
Projekt-Bucket | Ja | Ja | Ja | Der Standard-Bucket wird mithilfe der CreateProjectV1-API erstellt. Unterstützung für das Erstellen und Löschen von Projekt-Buckets wurde in Update Release 16 hinzugefügt. |
Projektteammitglied | Ja | Ja | Ja | Verwenden Sie für den Erstellungsvorgang die CreateTeamMemberV1-API. |
Project | Ja | Ja | Nr. | Vorgänge mit den folgenden Feldern werden nicht unterstützt: StateCode, BulkGenerationStatus, GlobalRevisionToken, CalendarID, Aufwand, EffortCompleted, EffortRemaining, Fortschritt, Fertigstellen, TaskEarliestStart und Dauer. |
Projektprüflisten | Ja | Ja | Ja | |
Projektbeschriftung | Nein | Ja | Nein | Etikettennamen können geändert werden. Diese Funktion ist nur für Project for the Web verfügbar. Beschriftungen werden erstellt, wenn Sie zum ersten Mal ein Projekt öffnen. |
Zu beschriftende Projektaufgabe | Ja | Nein | Ja | Diese Funktion ist nur für Project for the Web verfügbar. |
Projektsprint | Ja | Ja | Ja | Das Start-Feld muss ein Datum vor dem Fertig-Feld haben. Sprints für dasselbe Projekt dürfen sich nicht überschneiden. Diese Funktion ist nur für Project for the Web verfügbar. |
Projektziel | Ja | Ja | Ja | Vorgänge mit den folgenden Feldern werden nicht unterstützt: DescriptionPlainText, TaskDisplayOrder |
Projektaufgabe für Ziel | Ja | Keine | Ja | Vorgänge mit den folgenden Feldern werden nicht unterstützt: TaskDisplayOrder |
*Ressourcen-Zuweisungsdatensätze werden nicht aktualisiert. Stattdessen kann der alte Datensatz gelöscht und ein neuer Datensatz erstellt werden. Zum Aktualisieren der Konturen der Ressourcenzuweisung steht eine separate API zur Verfügung.
Diese ID-Eigenschaft ist optional. Wenn die ID-Eigenschaft angegeben ist, versucht das System, sie zu verwenden, und löst eine Ausnahme aus, wenn sie nicht verwendet werden kann. Wenn sie nicht bereitgestellt wird, generiert das System sie.
Einschränkungen und bekannte Probleme
Die folgende Liste zeigt Einschränkungen und bekannte Probleme:
Project Schedule APIs können nur von Benutzern mit Microsoft Project-Lizenz verwendet werden. Sie können nicht verwendet werden von:
- Anwendungsbenutzer
- Systembenutzern
- Integrationsbenutzern
- Andere Benutzer, die nicht über die erforderliche Lizenz verfügen
Jeder OperationSet kann nur maximal 200 Operationen haben.
Jeder Benutzer kann nur maximal 10 offene OperationSets haben.
Jeder Vorgang zum Aktualisieren der Ressourcenzuweisungskontur zählt als ein einzelner Vorgang.
Jede Liste aktualisierter Konturen kann maximal 100 Zeitscheiben enthalten.
OperationSet-Fehlerstatus und -Fehlerprotokolle sind derzeit nicht verfügbar.
Es gibt maximal 400 Sprints pro Projekt.
Fehlerbehandlung
- Um die aus den Operations-Sätzen generierten Fehler zu überprüfen, gehen Sie zu Einstellungen>Integration planen>Operationssätze.
- Um vom Project Schedule Service generierte Fehler zu überprüfen, gehen Sie auf Einstellungen>Planungsintegration>PSS Fehlerprotokolle.
Bearbeiten der Konturen der Ressourcenzuweisung
Im Gegensatz zu allen anderen Projektplanungs-APIs, die eine Entität aktualisieren, ist die Ressourcenzuweisungskontur-API ausschließlich für Aktualisierungen eines einzelnen Felds, msdyn_plannedwork, auf einer einzelnen Entität, msydn_resourceassignment, verantwortlich.
Der gegebene Zeitplanmodus ist:
- Feste Einheiten
- Der Projektkalender ist auf montags, dienstags, donnerstags und freitags von 9:00 bis 17:00 Uhr (pazifische Zeit) festgelegt. (Mittwochs wird nicht gearbeitet.)
- Der Ressourcenkalender ist von 9:00 bis 13:00 Uhr (pazifische Zeit) von montags bis freitags festgelegt.
Diese Zuweisung erfolgt für eine Woche und umfasst vier Stunden pro Tag, da der Ressourcenkalender von 9:00 bis 13:00 Uhr (Pazifikzeit) reicht, also vier Stunden pro Tag.
Aufgabe | Startdatum | Enddatum | Menge | 13.6.2022 | 14.6.2022 | 15.6.2022 | 16.6.2022 | 17.6.2022 | |
---|---|---|---|---|---|---|---|---|---|
9-1 Arbeitskraft | T1 | 13.6.2022 | 17.6.2022 | 20 | 4 | 4 | 4 | 4 | 4 |
Wenn Sie beispielsweise möchten, dass die Arbeitskraft diese Woche nur drei Stunden pro Tag arbeitet und eine Stunde für andere Aufgaben einplanen soll.
UpdatedContours-Beispiel-Nutzlast
[{
"minutes":900.0,
"start":"2022-06-13T00:00:00-07:00",
"end":"2022-06-18T00:00:00-07:00"
}]
Dies ist die Zuweisung, nachdem die Update Contour Schedule API ausgeführt wurde.
Task | Startdatum | Enddatum | Menge | 13.6.2022 | 14.6.2022 | 15.6.2022 | 16.6.2022 | 17.6.2022 | |
---|---|---|---|---|---|---|---|---|---|
9-1 Arbeitskraft | T1 | 13.6.2022 | 17.6.2022 | 15 | 3 | 3 | 3 | 3 | 3 |
Beispielszenario
In diesem Szenario erstellen Sie ein Projekt, ein Teammitglied, vier Aufgaben und zwei Ressourcenzuweisungen. Als Nächstes aktualisieren Sie eine Aufgabe, aktualisieren das Projekt, aktualisieren eine Ressourcenzuweisungskontur, löschen eine Aufgabe, löschen eine Ressourcenzuweisung und erstellen eine Aufgabenabhängigkeit.
Entity project = CreateProject();
project.Id = CallCreateProjectAction(project);
var projectReference = project.ToEntityReference();
var teamMember = new Entity("msdyn_projectteam", Guid.NewGuid());
teamMember["msdyn_name"] = $"TM {DateTime.Now.ToShortTimeString()}";
teamMember["msdyn_project"] = projectReference;
var createTeamMemberResponse = CallCreateTeamMemberAction(teamMember);
var description = $"My demo {DateTime.Now.ToShortTimeString()}";
var operationSetId = CallCreateOperationSetAction(project.Id, description);
var task1 = GetTask("1WW", projectReference);
var task2 = GetTask("2XX", projectReference, task1.ToEntityReference());
var task3 = GetTask("3YY", projectReference);
var task4 = GetTask("4ZZ", projectReference);
var assignment1 = GetResourceAssignment("R1", teamMember, task2, project);
var assignment2 = GetResourceAssignment("R2", teamMember, task3, project);
var task1Response = CallPssCreateAction(task1, operationSetId);
var task2Response = CallPssCreateAction(task2, operationSetId);
var task3Response = CallPssCreateAction(task3, operationSetId);
var task4Response = CallPssCreateAction(task4, operationSetId);
var assignment1Response = CallPssCreateAction(assignment1, operationSetId);
var assignment2Response = CallPssCreateAction(assignment2, operationSetId);
task2["msdyn_subject"] = "Updated Task";
var task2UpdateResponse = CallPssUpdateAction(task2, operationSetId);
project["msdyn_subject"] = $"Proj update {DateTime.Now.ToShortTimeString()}";
var projectUpdateResponse = CallPssUpdateAction(project, operationSetId);
List<UpdatedContour> updatedContours = new List<UpdatedContour>();
UpdatedContour updatedContour = new UpdatedContour();
updatedContour.Start = DateTime.UtcNow.Date;
updatedContour.End = DateTime.UtcNow.Date.AddDays(1);
updatedContour.Minutes = 120;
updatedContours.Add(updatedContour);
String serializedUpdate = JsonConvert.SerializeObject(updatedContours);
var updateContoursResponse = CallPssUpdateContourAction(assignment1.Id, serializedUpdate, operationSetId);
var task4DeleteResponse = CallPssDeleteAction(task4.Id.ToString(), task4.LogicalName, operationSetId);
var assignment2DeleteResponse = CallPssDeleteAction(assignment2.Id.ToString(), assignment2.LogicalName, operationSetId);
var dependency1 = GetTaskDependency(project, task2, task3);
var dependency1Response = CallPssCreateAction(dependency1, operationSetId);
CallExecuteOperationSetAction(operationSetId);
Console.WriteLine("Done....");
Zusätzliche Beispiele
#region Call actions --- Sample code ----
/// <summary>
/// Calls the action to create an operationSet
/// </summary>
/// <param name="projectId">project id for the operations to be included in this operationSet</param>
/// <param name="description">description of this operationSet</param>
/// <returns>operationSet id</returns>
private string CallCreateOperationSetAction(Guid projectId, string description)
{
OrganizationRequest operationSetRequest = new OrganizationRequest("msdyn_CreateOperationSetV1");
operationSetRequest["ProjectId"] = projectId.ToString();
operationSetRequest["Description"] = description;
OrganizationResponse response = organizationService.Execute(operationSetRequest);
return response["OperationSetId"].ToString();
}
/// <summary>
/// Calls the action to create an entity
/// </summary>
/// <param name="entity">Scheduling entity</param>
/// <param name="operationSetId">operationSet id</param>
/// <returns>OperationSetResponse</returns>
private OperationSetResponse CallPssCreateAction(Entity entity, string operationSetId)
{
OrganizationRequest operationSetRequest = new OrganizationRequest("msdyn_PssCreateV1");
operationSetRequest["Entity"] = entity;
operationSetRequest["OperationSetId"] = operationSetId;
return GetOperationSetResponseFromOrgResponse(organizationService.Execute(operationSetRequest));
}
/// <summary>
/// Calls the action to update an entity
/// </summary>
/// <param name="entity">Scheduling entity</param>
/// <param name="operationSetId">operationSet Id</param>
/// <returns>OperationSetResponse</returns>
private OperationSetResponse CallPssUpdateAction(Entity entity, string operationSetId)
{
OrganizationRequest operationSetRequest = new OrganizationRequest("msdyn_PssUpdateV1");
operationSetRequest["Entity"] = entity;
operationSetRequest["OperationSetId"] = operationSetId;
return GetOperationSetResponseFromOrgResponse(organizationService.Execute(operationSetRequest));
}
/// <summary>
/// Calls the action to update an entity
/// </summary>
/// <param name="recordId">Id of the record to be deleted</param>
/// <param name="entityLogicalName">Entity logical name of the record</param>
/// <param name="operationSetId">OperationSet Id</param>
/// <returns>OperationSetResponse</returns>
private OperationSetResponse CallPssDeleteAction(string recordId, string entityLogicalName, string operationSetId)
{
OrganizationRequest operationSetRequest = new OrganizationRequest("msdyn_PssDeleteV1");
operationSetRequest["RecordId"] = recordId;
operationSetRequest["EntityLogicalName"] = entityLogicalName;
operationSetRequest["OperationSetId"] = operationSetId;
return GetOperationSetResponseFromOrgResponse(organizationService.Execute(operationSetRequest));
}
/// <summary>
/// Calls the action to update a Resource Assignment contour
/// </summary>
/// <param name="resourceAssignmentId">Id of the resource assignment to be updated</param>
/// <param name="serializedUpdates">JSON formatted contour updates</param>
/// <param name="operationSetId">operationSet id</param>
/// <returns>OperationSetResponse</returns>
private OperationSetResponse CallPssUpdateContourAction(string resourceAssignmentId, string serializedUpdates string operationSetId)
{
OrganizationRequest operationSetRequest = new OrganizationRequest("msdyn_PssUpdateResourceAssignmentContourV1");
operationSetRequest["ResourceAssignmentId"] = resourceAssignmentId;
operationSetRequest["UpdatedContours"] = serializedUpdates;
operationSetRequest["OperationSetId"] = operationSetId;
return GetOperationSetResponseFromOrgResponse(OrganizationService.Execute(operationSetRequest));
}
/// <summary>
/// Calls the action to execute requests in an operationSet
/// </summary>
/// <param name="operationSetId">operationSet id</param>
/// <returns>OperationSetResponse</returns>
private OperationSetResponse CallExecuteOperationSetAction(string operationSetId)
{
OrganizationRequest operationSetRequest = new OrganizationRequest("msdyn_ExecuteOperationSetV1");
operationSetRequest["OperationSetId"] = operationSetId;
return GetOperationSetResponseFromOrgResponse(organizationService.Execute(operationSetRequest));
}
/// <summary>
/// This can be used to abandon an operationSet that is no longer needed
/// </summary>
/// <param name="operationSetId">operationSet id</param>
/// <returns>OperationSetResponse</returns>
protected OperationSetResponse CallAbandonOperationSetAction(Guid operationSetId)
{
OrganizationRequest operationSetRequest = new OrganizationRequest("msdyn_AbandonOperationSetV1");
operationSetRequest["OperationSetId"] = operationSetId.ToString();
return GetOperationSetResponseFromOrgResponse(organizationService.Execute(operationSetRequest));
}
/// <summary>
/// Calls the action to create a new project
/// </summary>
/// <param name="project">Project</param>
/// <returns>project Id</returns>
private Guid CallCreateProjectAction(Entity project)
{
OrganizationRequest createProjectRequest = new OrganizationRequest("msdyn_CreateProjectV1");
createProjectRequest["Project"] = project;
OrganizationResponse response = organizationService.Execute(createProjectRequest);
var projectId = Guid.Parse((string)response["ProjectId"]);
return projectId;
}
/// <summary>
/// Calls the action to create a new project team member
/// </summary>
/// <param name="teamMember">Project team member</param>
/// <returns>project team member Id</returns>
private string CallCreateTeamMemberAction(Entity teamMember)
{
OrganizationRequest request = new OrganizationRequest("msdyn_CreateTeamMemberV1");
request["TeamMember"] = teamMember;
OrganizationResponse response = organizationService.Execute(request);
return (string)response["TeamMemberId"];
}
private OperationSetResponse GetOperationSetResponseFromOrgResponse(OrganizationResponse orgResponse)
{
return JsonConvert.DeserializeObject<OperationSetResponse>((string)orgResponse.Results["OperationSetResponse"]);
}
private EntityCollection GetDefaultBucket(EntityReference projectReference)
{
var columnsToFetch = new ColumnSet("msdyn_project", "msdyn_name");
var getDefaultBucket = new QueryExpression("msdyn_projectbucket")
{
ColumnSet = columnsToFetch,
Criteria =
{
Conditions =
{
new ConditionExpression("msdyn_project", ConditionOperator.Equal, projectReference.Id),
new ConditionExpression("msdyn_name", ConditionOperator.Equal, "Bucket 1")
}
}
};
return organizationService.RetrieveMultiple(getDefaultBucket);
}
private Entity GetBucket(EntityReference projectReference)
{
var bucketCollection = GetDefaultBucket(projectReference);
if (bucketCollection.Entities.Count > 0)
{
return bucketCollection[0].ToEntity<Entity>();
}
throw new Exception($"Please open project with id {projectReference.Id} in the Dynamics UI and navigate to the Tasks tab");
}
private Entity CreateProject()
{
var project = new Entity("msdyn_project", Guid.NewGuid());
project["msdyn_subject"] = $"Proj {DateTime.Now.ToShortTimeString()}";
return project;
}
private Entity GetTask(string name, EntityReference projectReference, EntityReference parentReference = null)
{
var task = new Entity("msdyn_projecttask", Guid.NewGuid());
task["msdyn_project"] = projectReference;
task["msdyn_subject"] = name;
task["msdyn_effort"] = 4d;
task["msdyn_scheduledstart"] = DateTime.Today;
task["msdyn_scheduledend"] = DateTime.Today.AddDays(5);
task["msdyn_start"] = DateTime.Now.AddDays(1);
task["msdyn_projectbucket"] = GetBucket(projectReference).ToEntityReference();
task["msdyn_LinkStatus"] = new OptionSetValue(192350000);
//Custom field handling
/*
task["new_custom1"] = "Just my test";
task["new_age"] = 98;
task["new_amount"] = 591.34m;
task["new_isready"] = new OptionSetValue(100000000);
*/
if (parentReference == null)
{
task["msdyn_outlinelevel"] = 1;
}
else
{
task["msdyn_parenttask"] = parentReference;
}
return task;
}
private Entity GetResourceAssignment(string name, Entity teamMember, Entity task, Entity project)
{
var assignment = new Entity("msdyn_resourceassignment", Guid.NewGuid());
assignment["msdyn_projectteamid"] = teamMember.ToEntityReference();
assignment["msdyn_taskid"] = task.ToEntityReference();
assignment["msdyn_projectid"] = project.ToEntityReference();
assignment["msdyn_name"] = name;
return assignment;
}
protected Entity GetTaskDependency(Entity project, Entity predecessor, Entity successor)
{
var taskDependency = new Entity("msdyn_projecttaskdependency", Guid.NewGuid());
taskDependency["msdyn_project"] = project.ToEntityReference();
taskDependency["msdyn_predecessortask"] = predecessor.ToEntityReference();
taskDependency["msdyn_successortask"] = successor.ToEntityReference();
taskDependency["msdyn_linktype"] = new OptionSetValue(192350000);
return taskDependency;
}
#endregion
#region OperationSetResponse DataContract --- Sample code ----
[DataContract]
public class OperationSetResponse
{
[DataMember(Name = "operationSetId")]
public Guid OperationSetId { get; set; }
[DataMember(Name = "operationSetDetailId")]
public Guid OperationSetDetailId { get; set; }
[DataMember(Name = "operationType")]
public string OperationType { get; set; }
[DataMember(Name = "recordId")]
public string RecordId { get; set; }
[DataMember(Name = "correlationId")]
public string CorrelationId { get; set; }
}
#endregion
#region UpdatedContour DataContract --- Sample code ----
[DataContract]
public class UpdatedContour
{
[DataMember(Name = "start")]
public DateTime Start { get; set; }
[DataMember(Name = "end")]
public DateTime End { get; set; }
[DataMember(Name = "minutes")]
public decimal Minutes { get; set; }
}
#endregion