Bruk API-er for prosjektplan til å utføre operasjoner med planleggingsenheter
Gjelder for: Project Operations for ressursbaserte/ikke-lagerbaserte scenarioer, Lite-distribusjon – avtale til proformafakturering.
Planleggingsenheter
API-er for prosjektplan gir mulighet til å utføre operasjoner for oppretting, oppdatering og sletting med planleggingsenheter. Disse enhetene administreres via planleggingsmotoren i Project for the web. Oppretting, oppdatering og sletting med planleggingsenheter var begrenser i tidligere versjoner av Dynamics 365 Project Operations.
Tabellen nedenfor viser en fullstendig liste over prosjekttidsplanens enheter.
Enhetsnavn | Logisk navn for enhet |
---|---|
Project | msdyn_project |
Prosjektoppgave | msdyn_projecttask |
Avhengighet for prosjektoppgaver | msdyn_projecttaskdependency |
Ressurstilordning | msdyn_resourceassignment |
Prosjektsamling | msdyn_projectbucket |
Prosjektteammedlem | msdyn_projectteam |
Prosjektsjekklister | msdyn_projectchecklist |
Prosjektetikett | msdyn_projectlabel |
Prosjektoppgave til etikett | msdyn_projecttasktolabel |
Prosjektsprint | msdyn_projectsprint |
OperationSet
OperationSet er et enhetsarbeidsmønster som kan brukes når flere forespørsler som påvirker tidsplanen, må behandles i en transaksjon.
API-er for prosjektplan
Nedenfor vises en liste over gjeldende API-er for prosjektplan.
API | Bekrivelse |
---|---|
msdyn_CreateProjectV1 | Denne API-en brukes til å opprette et prosjekt. Prosjektet og standard prosjektsamling opprettes umiddelbart. Prosjektopprettelse kan også utføres ved å legge til en rad i prosjekttabellen ved hjelp av standard Dataverse-API-er. Denne prosessen oppretter ikke en standardsamling for prosjektet, men har kanskje bedre ytelse. |
msdyn_CreateTeamMemberV1 | Denne API-en brukes til å opprette et prosjektteammedlem. Teammedlemsoppføringen opprettes umiddelbart. Teammedlemsopprettelse kan også utføres ved å legge til en rad i prosjektteammedlemstabellen ved hjelp av standard Dataverse-API-er. |
msdyn_CreateOperationSetV1 | Denne API-en brukes til å planlegge flere forespørsler som må utføres i en transaksjon. |
msdyn_PssCreateV1 | Denne API-en brukes til å opprette en enhet. Enheten kan være en hvilken som helst av prosjektplanleggingsenhetene som støtter opprettingsoperasjonen. |
msdyn_PssCreateV2 | Denne API-en brukes til å opprette en enhet. Det fungerer som msdyn_PssCreateV1, men flere enheter kan opprettes i én handling. |
msdyn_PssUpdateV1 | Denne API-en brukes til å oppdatere en enhet. Enheten kan være en hvilken som helst av prosjektplanleggingsenhetene som støtter oppdateringsoperasjonen. |
msdyn_PssUpdateV2 | Denne API-en brukes til å oppdatere enheter. Det fungerer som msdyn_PssUpdateV1, men flere enheter kan oppdateres i én handling. |
msdyn_PssDeleteV1 | Denne API-en brukes til å slette en enhet. Enheten kan være en hvilken som helst av prosjektplanleggingsenhetene som støtter sletteoperasjonen. |
msdyn_PssDeleteV2 | Denne API-en brukes til å slette enheter. Det fungerer som msdyn_PssDeleteV1, men flere enheter kan slettes i én handling. |
msdyn_ExecuteOperationSetV1 | Denne API-en brukes til å kjøre alle operasjonene i det angitte operasjonssettet. |
msdyn_PssUpdateResourceAssignmentV1 | Denne API-en brukes til å oppdatere omfanget for planlagt arbeid med ressurstilordning. |
Bruk av API-er for prosjektplan med OperationSet
Ettersom oppføringer opprettes umiddelbart for både CreateProjectV1 og CreateTeamMemberV1, kan ikke disse API-ene brukes direkte i OperationSet. Du kan imidlertid bruke dem til å opprette de nødvendige oppføringene, opprette et OperationSet og deretter bruke de forhåndsopprettede oppføringene i OperationSet.
Støttede operasjoner
Planleggingsenhet | Opprette | Oppdater | Delete | Viktige hensyn |
---|---|---|---|---|
Prosjektoppgave | Ja | Ja | Ja | Feltene Progress, EffortCompleted og EffortRemaining kan redigeres i Project for the Web, men de kan ikke redigeres i Project Operations. |
Avhengighet for prosjektoppgaver | Ja | Nei | Ja | Oppføringer for prosjektoppgaveavhengighet oppdateres ikke. I stedet kan en gammel oppføring slettes, og en ny oppføring kan opprettes. |
Ressurstilordning | Ja | Ja* | Ja | Operasjoner med følgende felter støttes ikke: BookableResourceID, Effort, EffortCompleted, EffortRemaining og PlannedWork. |
Prosjektsamling | Ja | Ja | Ja | Standardsamlingen opprettes ved hjelp av API-en CreateProjectV1. Støtte for oppretting og sletting av prosjektsamlinger ble lagt til i oppdateringsversjon 16. |
Prosjektteammedlem | Ja | Ja | Ja | For oppretting bruker du API-en CreateTeamMemberV1. |
Project | Ja | Ja | No | Operasjoner med følgende felter støttes ikke: StateCode, BulkGenerationStatus, GlobalRevisionToken, CalendarID, Effort, EffortCompleted, EffortRemaining, Progress, Finish, TaskEarliestStart og Duration. |
Prosjektsjekklister | Ja | Ja | Ja | |
Prosjektetikett | Nei | Ja | Nei | Etikettnavn kan endres. Denne funksjonen er bare tilgjengelig for Project for the Web. Etiketter opprettes første gang du åpner et prosjekt. |
Prosjektoppgave til etikett | Ja | No | Ja | Denne funksjonen er bare tilgjengelig for Project for the Web. |
Prosjektsprint | Ja | Ja | Ja | Start-feltet må ha en dato som er før Fullfør-feltet. Sprinter for samme prosjekt kan ikke overlappe hverandre. Denne funksjonen er bare tilgjengelig for Project for the Web. |
Prosjektmål | Ja | Ja | Ja | Operasjoner med følgende felter støttes ikke: DescriptionPlainText, TaskDisplayOrder |
Prosjektoppgave til mål | Ja | Nei | Ja | Operasjoner med følgende felter støttes ikke: TaskDisplayOrder |
* Ressurstilordningsoppføringer oppdateres ikke. I stedet kan en gammel oppføring slettes, og en ny oppføring kan opprettes. Det finnes en egen API til oppdatering av profiler for ressurstilordning.
ID-egenskapen er valgfri. Hvis ID-egenskapen er angitt, prøver systemet å bruke den, og dette fører til et unntak hvis den ikke kan brukes. Hvis den ikke er angitt, genererer systemet den.
Begrensninger og kjente problemer
Listen nedenfor viser begrensninger og kjente problemer:
API-er for prosjektplan kan bare brukes av brukere med Microsoft Project-lisens. De kan ikke brukes av følgende:
- Applikasjonsbrukere
- Systembrukere
- Integreringsbrukere
- Andre brukere som ikke har den nødvendige lisensen
Hvert OperationSet kan bare ha maksimalt 200 operasjoner.
Hver bruker kan bare ha maksimalt 10 åpne OperationSets.
Hver oppdateringsoperasjon for omfanget av ressurstilordningen teller som én enkelt operasjon.
Hver liste over oppdaterte omfang kan inneholde maksimalt 100 tidssektorer.
OperationSet-feilstatus og -feillogger er ikke tilgjengelige for øyeblikket.
Det er en maksimumsgrense på 400 sprinter per prosjekt.
Feilbehandling
- Hvis du vil se gjennom feil som genereres fra operasjonssettene, går du til Innstillinger>Planlegg integrasjon>Operasjonssett.
- Hvis du vil se gjennom feil som genereres fra prosjektplantjenesten, går du til Innstilling>Planlegg integrering>Planlegg integrering.
Redigering av ressurstilordningsomfang
I motsetning til alle andre API-er for prosjektplanlegging som oppdaterer en enhet, er API-en for ressurstilordningsomfang kun ansvarlig for oppdateringer for ett enkelt felt, msdyn_plannedwork, på én enhet, msydn_resourceassignment.
Den gitte tidsplanmodusen er:
- faste enheter.
- Prosjektkalenderen er fra 09:00 til 17:00 (Stillehavskysten) mandag, tirsdag, torsdag og fredag. (Det er ikke arbeid på onsdager.)
- Ressurskalenderen er fra 09:00 til 13:00 (Stillehavskysten) mandag til fredag.
Denne tilordningen er for én uke og fire timer om dagen fordi ressurskalenderen er fra 09:00 til 13:00 (stillehavskysten), eller fire timer om dagen.
Oppgave | Startdato | Sluttdato | Mengde | 13.06.2022 | 14.06.2022 | 15.06.2022 | 16.06.2022 | 17.06.2022 | |
---|---|---|---|---|---|---|---|---|---|
9-1 arbeider | T1 | 13.06.2022 | 17.06.2022 | 20 | 4 | 4 | 4 | 4 | 4 |
Hvis du for eksempel vil at arbeideren bare skal arbeide tre timer hver dag denne uken og bruke en time på andre oppgaver.
Eksempelnyttelasten UpdatedContours
[{
"minutes":900.0,
"start":"2022-06-13T00:00:00-07:00",
"end":"2022-06-18T00:00:00-07:00"
}]
Dette er tilordningen etter at API-en for oppdatering av omfanget til tidsplanen er kjørt.
Oppgave | Startdato | Sluttdato | Antall | 13.06.2022 | 14.06.2022 | 15.06.2022 | 16.06.2022 | 17.06.2022 | |
---|---|---|---|---|---|---|---|---|---|
9-1 arbeider | T1 | 13.06.2022 | 17.06.2022 | 15 | 3 | 3 | 3 | 3 | 3 |
Eksempelscenario
I dette scenarioet skal du opprette et prosjekt, et teammedlem, fire oppgaver og to ressurstilordninger. Deretter skal du oppdatere én oppgave, oppdatere prosjektet, oppdatere et ressurstilordningsomfang, slette én oppgave, slette én ressurstilordning og opprette en aktivitetsavhengighet.
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....");
Flere eksempler
#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