Korišćenje API-ja za raspored projekata za izvođenje operacija sa entitetima raspoređivanja
Primenjuje se na: Projektne operacije za scenarije zasnovane na resursima/nenapukovane, Lite deployment - dogovor sa proforma fakturisanjem.
Entiteti za planiranje
API-je za planiranje projekta obezbeđuju mogućnost izvršavanja operacija kreiranja, ažuriranja i brisanja sa entitetima za planiranje. Tim entitetima se upravlja putem mehanizma za raspoređivanje u aplikaciji Project za veb. Operacije kreiranja, ažuriranja i brisanja sa entitetima za planiranje ograničene su u ranijim Dynamics 365 Project Operations izdanjima.
Sledeća tabela daje potpunu listu entiteta za raspored projekata.
Naziv entiteta | Logičko ime entiteta |
---|---|
Project | msdyn_project |
Projektni zadatak | msdyn_projecttask |
Zavisnost projektnog zadatka | msdyn_projecttaskdependency |
Dodela resursa | msdyn_resourceassignment |
Kontejner projekta | msdyn_projectbucket |
Član projektnog tima | msdyn_projectteam |
Liste za proveru projekta | msdyn_projectchecklist |
Oznaka projekta | msdyn_projectlabel |
Zavisnost projektnog zadataka i oznake | msdyn_projecttasktolabel |
Sprint projekta | msdyn_projectsprint |
OperationSet
Entitet OperationSet je obrazac jedinice rada koji se može koristiti kada se u transakciji mora obraditi nekoliko zahteva koji utiču na raspored.
API rasporeda projekata
Sledi lista aktuelnih API-ja za raspored projekata.
API | Opis |
---|---|
msdyn_CreateProjectV1 | Ovaj API se koristi za kreiranje projekta. Projekat i podrazumevani kontejner projekta kreiraju se odmah. Kreiranje projekta se takođe može uraditi dodavanjem reda u tabelu projekata pomoću standardnih Dataverse API-ja. Ovaj proces neće kreirati podrazumevanu kofu za projekat, ali će možda imati bolje performanse. |
msdyn_CreateTeamMemberV1 | Ovaj API se koristi za kreiranje člana projektnog tima. Evidencija člana tima kreira se odmah. Kreiranje člana tima može se uraditi i dodavanjem reda u tabelu "Član projektnog tima" koristeći standardne Dataverse API-je. |
msdyn_CreateOperationSetV1 | Ovaj API se koristi za zakazivanje nekoliko zahteva koji se moraju izvršiti u okviru transakcije. |
msdyn_PssCreateV1 | Ovaj API se koristi za kreiranje entiteta. Entitet može biti bilo koji entitet raspoređivanja projekta koji podržava operaciju kreiranja. |
msdyn_PssCreateV2 | Ovaj API se koristi za kreiranje entiteta. Funkcioniše kao msdyn_PssCreateV1 , ali se u jednoj radnji može kreirati više entiteta. |
msdyn_PssUpdateV1 | Ovaj API se koristi za ažuriranje entiteta. Entitet može biti bilo koji entitet raspoređivanja projekta koji podržava operaciju ažuriranja. |
msdyn_PssUpdateV2 | Ovaj API se koristi za ažurirane entitete. Radi kao msdyn_PssUpdateV1 , ali se više entiteta može ažurirati u jednoj radnji. |
msdyn_PssDeleteV1 | Ovaj API se koristi za brisanje entiteta. Entitet može biti bilo koji entitet raspoređivanja projekta koji podržava operaciju brisanja. |
msdyn_PssDeleteV2 | Ovaj API se koristi za brisanje entiteta. Funkcioniše kao msdyn_PssDeleteV1 , ali se više entiteta može izbrisati u jednoj radnji. |
msdyn_ExecuteOperationSetV1 | Ovaj API se koristi za izvršavanje svih operacija unutar datog skupa operacija. |
msdyn_PssUpdateResourceAssignmentV1 | Ovaj API se koristi za ažuriranje konture planiranog rada dodele resursa. |
Korišćenje API-ja sa planom projekta pomoću programa OperationSet
Pošto se zapisi kreiraju odmah za CreateProjectV1 i CreateTeamMemberV1 , ovi API-je ne mogu direktno da se koriste uprogramu OperationSet . Međutim, možete da ih koristite za kreiranje potrebnih zapisa, kreiranje operationSet-a , azatim korišćenje unapred kreiranih zapisa u programu OperationSet.
Podržane operacije
Entitet planiranja | Kreiranje | Ažuriranje | Izbrisi | Važna razmatranja |
---|---|---|---|---|
Projektni zadatak | Da | Da | Da | Polja Progres,EffortCompleted i EffortRemaining mogu da se uređuju u projektu za Web, ali se ne mogu uređivati u operacijama projekta. |
Zavisnost projektnog zadatka | Da | No | Da | Zapisi zavisnosti projektnih zadataka se ne ažuriraju. Umesto toga, stari zapis može da se izbriše i može da se kreira novi zapis. |
Dodela resursa | Da | Da* | Da | Operacije sa sledećim poljima nisu podržane: BookableResourceID,Effort,EffortCompleted,EffortRemaining i PlannedWork. |
Kontejner projekta | Da | Da | Da | Podrazumevana kofa se kreira pomoću API-ja CreateProjectV1 . Podrška za kreiranje i brisanje kontejnera projekta je dodata u izdanju 16 ažuriranja. |
Član projektnog tima | Da | Da | Da | Za operaciju kreiranja koristite API CreateTeamMemberV1 . |
Project | Da | Da | Operacije sa sledećim poljima nisu podržane: StateCode,BulkGenerationStatus,GlobalRevisionToken,CalendarID,Effort,EffortCompleted,EffortRemaining,Progress,Finish,TaskEarliestStart i Duration. | |
Liste za proveru projekta | Da | Da | Da | |
Oznaka projekta | No | Da | No | Nazivi oznaka se mogu promeniti. Ova funkcija je dostupna samo za Projekat za Web. Oznake se kreiraju kada prvi put otvorite projekat. |
Zavisnost projektnog zadataka i oznake | Da | No | Da | Ova funkcija je dostupna samo za Projekat za Web. |
Sprint projekta | Da | Da | Da | Polje "Start " mora imati datum raniji od polja Završi . Sprintevi za isti projekat ne mogu da se preklapaju. Ova funkcija je dostupna samo za Projekat za Web. |
Cilj projekta | Da | Da | Da | Operacije sa sledećim poljima nisu podržane: DescriptionPlainText, TaskDisplayOrder |
Zavisnost projektnog zadataka i cilja | Da | No | Da | Operacije sa sledećim poljima nisu podržane: TaskDisplayOrder |
* Zapisi dodeljivanje resursa se ne ažuriraju. Umesto toga, stari zapis može da se izbriše i može da se kreira novi zapis. Obezbeđen je poseban API za ažuriranje kontura dodele resursa.
Svojstvo ID je opcionalno. Ako je obezbeđen, sistem pokušava da ga koristi i baca izuzetak ako ne može da se koristi. Ako nije obezbeđen, sistem ga generiše.
Ograničenja i poznati problemi
Sledi lista ograničenja i poznatih problema:
API-je za plan projekta mogu da koriste samo korisnici sa licencom za Microsoft Project. Ne mogu ih koristiti:
- Korisnici aplikacije
- Korisnici sistema
- Korisnici integracije
- Ostali korisnici koji nemaju potrebnu licencu
Svaki OperationSet može da ima najviše 200 operacija.
Svaki korisnik može imati najviše 10 otvorenih OperationSets .
Project Operations trenutno podržava maksimalno 1000 ukupnih zadataka na projektu.
Svaka operacija ažuriranja konture dodele resursa se računa kao jedna operacija.
Svaka lista ažuriranih kontura može da sadrži najviše 100 vremenskih isečaka.
Status otkazivanja programa OperationSet i evidencije otkazivanja trenutno nisu dostupni.
Postoji najviše 400 sprinta po projektu.
Oznake su trenutno dostupne samo za Project for the Web.
Oznake se kreiraju kada prvi put otvorite projekat.
Ima najviše 10 golova po projektu.
Svaki zadatak se može jednom pojaviti u projektnog zadatka cilju.
Rukovanje greškama
- Da biste pregledali greške generisane iz skupova operacija, idite na skupove operacija integracije>>sa postavkama.
- Da biste pregledali greške generisane iz usluge projektnog rasporeda, idite na evidencije>OS grešaka>za planiranje postavki.
Uređivanje kontura dodele resursa
Za razliku od svih drugih API-ja za planiranje koji ažuriraju entitet, API za konturu dodele resursa je isključivo odgovoran za ažuriranja jednog polja, msdyn_plannedwork, na jednim entitetom, msydn_resourceassignment.
Dati režim rasporeda je:
- fiksne jedinice.
- Kalendar projekta je od 9:00 do 17:00 časova (po pacifičkom vremenu) u ponedeljak, utorak, četvrtak i petak. (Sredom nema posla.)
- Kalendar resursa je od 9:00 do 1:00 popodne (pacifičko vreme) od ponedeljka do petka.
Ovaj zadatak je za nedelju dana, četiri sata dnevno. To je zato što je kalendar resursa od 9:00 do 1:00 popodne (pacifičko vreme), odnosno četiri sata dnevno.
Zadatak | Datum početka | Datum završetka | Količina | 13.6.2022. | 14.6.2022. | 15.6.2022. | 16.6.2022. | 17.6.2022. | |
---|---|---|---|---|---|---|---|---|---|
9-1 radnik | T1 | 13.6.2022. | 17.6.2022. | 20 | 4 | 4 | 4 | 4 | 4 |
Na primer, ako želite da radnik radi samo tri sata svakog dana ove sedmice i omogućite jedan sat za druge zadatke.
AžuriranoContours uzorak tovara
[{
"minutes":900.0,
"start":"2022-06-13T00:00:00-07:00",
"end":"2022-06-18T00:00:00-07:00"
}]
Ovo je dodela nakon što se pokrene API za ažuriranje rasporeda kontura.
Zadatak | Datum početka | Datum završetka | Količina | 13.6.2022. | 14.6.2022. | 15.6.2022. | 16.6.2022. | 17.6.2022. | |
---|---|---|---|---|---|---|---|---|---|
9-1 radnik | T1 | 13.6.2022. | 17.6.2022. | 15 | 3 | 3 | 3 | 3 | 3 |
Uzorak scenarija
U ovom scenariju kreirate projekat, člana tima, četiri zadatka i dve dodele resursa. Zatim ažurirate jedan zadatak, ažurirate projekat, ažurirate konturu dodele resursa, izbrišete jedan zadatak, izbrišete jednu dodelu resursa i kreirate zavisnost od zadatka.
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....");
Dodatni uzorci
#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
Povratne informacije
https://aka.ms/ContentUserFeedback.
Stiže uskoro: Tokom 2024. godine postepeno ćemo ukidati probleme sa uslugom GitHub kao mehanizam povratnih informacija za sadržaj i zameniti ga novim sistemom povratnih informacija. Dodatne informacije potražite u članku:Prosledite i prikažite povratne informacije za