Projektütemezés API-k használata műveletek végrehajtásához az Ütemező entitásokkal

Vonatkozik: Project Operations erőforrás-/nem készletalapú forgatókönyvekhez, egyszerű üzembe helyezés – proforma számlázás.

Ütemezési entitások

A projektütemezési API-k lehetővé teszik létrehozási, frissítési és törlési műveletek végrehajtását ütemezési entitásokkal . Ezeket az entitásokat a Project for the web ütemezési motorja kezeli. Az ütemezési entitásokkal végzett létrehozási, frissítési és törlési műveletek a korábbi Dynamics 365 Project Operations kiadásokban korlátozottak voltak.

Az alábbi táblázat a Projektütemezési entitások teljes listáját tartalmazza.

Entitás neve Entitás logikai neve
Project msdyn_project
Projektfeladat msdyn_projecttask
Projektfeladat függősége msdyn_projecttaskdependency
Erőforrás-hozzárendelés msdyn_resourceassignment
Projektgyűjtő msdyn_projectbucket
Projektcsoporttag msdyn_projectteam
Projekt-ellenőrzőlisták msdyn_projectchecklist
Projektcímke msdyn_projectlabel
Projektfeladat címkéhez msdyn_projecttasktolabel
Projektfutam msdyn_projectsprint

Műveleti készlet

Az OperationSet egy munkaegység-minta, amely akkor használható, ha egy tranzakción belül több ütemezést is fel kell dolgozni, amely a kérelmeket érinti.

Projektütemezési API-k

A következő lista az aktuális Projektütemezési API-kat sorolja fel.

API Description
msdyn_CreateProjectV1 Ez az API egy projekt létrehozására szolgál. A projekt és az alapértelmezett projektgyűjtő azonnal létrejön. A projekt létrehozása úgy is elvégezhető, hogy hozzáad egy sort a projekttáblához szabványos Dataverse API-k használatával. Ez a folyamat nem hoz létre alapértelmezett gyűjtőt a projekthez, de jobb teljesítményt nyújthat.
msdyn_CreateTeamMemberV1 Ez az API egy projektcsoporttag létrehozására szolgál. A csoporttag-rekord azonnal létrejön. A csapattagok létrehozása úgy is elvégezhető, hogy szabványos API-k használatával Dataverse hozzáad egy sort a Project Team Member táblához.
msdyn_CreateOperationSetV1 Ez az API több olyan kérés ütemezésére használható, amelyeket egy tranzakción belül kell végrehajtani.
msdyn_PssCreateV1 Ez az API egy entitás létrehozására szolgál. Az entitás a létrehozási műveletet támogató bármely Projektütemezési entitás lehet.
msdyn_PssCreateV2 Ez az API egy entitás létrehozására szolgál. Úgy működik, mint msdyn_PssCreateV1, de egy művelettel több entitás is létrehozható.
msdyn_PssUpdateV1 Ez az API egy entitás frissítésére szolgál. Az entitás a frissítés műveletet támogató bármely Projektütemezési entitás lehet.
msdyn_PssUpdateV2 Ez az API frissített entitásokhoz használatos. Úgy működik, mint msdyn_PssUpdateV1, de egy művelettel több entitás is frissíthető.
msdyn_PssDeleteV1 Ez az API egy entitás törlésére szolgál. Az entitás a törlés műveletet támogató bármely Projektütemezési entitás lehet.
msdyn_PssDeleteV2 Ez az API entitások törlésére szolgál. Úgy működik, mint msdyn_PssDeleteV1, de több entitás is törölhető egy művelettel.
msdyn_ExecuteOperationSetV1 Ez az API az adott művelethalmazon belüli összes művelet végrehajtására használható.
msdyn_PssUpdateResourceAssignmentV1 Az API egy erőforrás-hozzárendelés munkakontúrjának frissítésére használható.

Projektütemezési API-k használata az OperationSet készlettel

Mivel a rekordok azonnal létrejönnek a CreateProjectV1 és a CreateTeamMemberV1 számára is, ezek az API-k nem használhatók közvetlenül az OperationSet készletben. Használhatja őket azonban a szükséges rekordok létrehozásához, egy OperationSet létrehozásához, majd az OperationSet előre létrehozott rekordjainak használatához.

Támogatott műveletek

Ütemezési entitás Létrehozás Update Delete Fontos tényezők
Projektfeladat Igen Igen Igen Az Előrehaladás,ErőfeszítésBefejeződött és Hátralévő mennyiség mezők szerkeszthetők a Webes Projectben, de nem szerkeszthetők a Project Operations programban.
Projektfeladat függősége Igen No Igen A projektfeladat függőségi rekordok nem frissülnek. Ehelyett egy régi rekord törölhető, és új rekord is létrehozható.
Erőforrás-hozzárendelés Igen Igen* Igen A következő mezőkkel végzett műveletek nem támogatottak: BookableResourceID,Effort,EffortCompleted,EffortRemaining és PlannedWork.
Projektgyűjtő Igen Igen Igen Az alapértelmezett gyűjtő a CreateProjectV1 API használatával jön létre. A projektgyűjtők létrehozásának és törlésének támogatása a 16. kiadású frissítésben lett hozzáadva.
A projekt csapattagja Igen Igen Igen A létrehozási művelethez használja a CreateTeamMemberV1 API-t.
Project Igen Igen A következő mezőkkel végzett műveletek nem támogatottak: StateCode,BulkGenerationStatus,GlobalRevisionToken,CalendarID,Effort,EffortCompleted,EffortRemaining,Progress,Finish,TaskEarliestStart és Duration.
Projekt-ellenőrzőlisták Igen Igen Igen
Projektcímke No Igen No A címkenevek módosíthatók. Ez a funkció csak a Webes Projektben érhető el. A címkék a projekt első megnyitásakor jönnek létre.
Projektfeladat címkéhez Igen No Igen Ez a funkció csak a Webes Projektben érhető el.
Projektfutam Igen Igen Igen A Kezdés mezőnek korábbinak kell lennie, mint a Befejezés mezőnek. Ugyanannak a projektnek a futamai nem fedhetik át egymást. Ez a funkció csak a Webes Projektben érhető el.
Projektcél Igen Igen Igen A következő mezőkkel végzett műveletek nem támogatottak: DescriptionPlainText, TaskDisplayOrder
Projektfeladatból cél Igen No Igen A következő mezőkkel végzett műveletek nem támogatottak: TaskDisplayOrder

* Az erőforrás-hozzárendelési rekordok nem frissülnek. Ehelyett a régi rekord törölhető, és új rekord is létrehozható. Külön API-t biztosítottunk az Erőforráshozzárendelési-kontúrok frissítéséhez.

Ez az azonosító-tulajdonság nem kötelező. Ha meg van adva, a rendszer megpróbálja használni, és kivételt dob, ha nem használható. Ha nincs megadva, a rendszer generálja.

Korlátozások és ismert problémák

Az alábbiakban felsoroljuk a korlátozásokat és az ismert problémákat:

  • A Project Schedule API-kat csak a Microsoft Project licenccel rendelkező felhasználók használhatják. Nem használhatják:

    • Alkalmazásfelhasználók
    • Rendszerfelhasználók
    • Integrációs felhasználók
    • Más felhasználók, akik nem rendelkeznek a szükséges licenccel
  • Minden műveletkészlet legfeljebb 200 művelettel rendelkezhet.

  • Minden felhasználónak legfeljebb 10 nyitott műveleti készlete lehet.

  • A Project Operations jelenleg legfeljebb 500 projektfeladatot támogat.

  • Minden erőforrás-hozzárendelési kontúrozás művelet egy műveletnek számít.

  • A frissített termékek listája legfeljebb 100 időszeletet tartalmazhat.

  • Az OperationSet hibaállapota és hibanaplói jelenleg nem érhetők el.

  • Projektenként legfeljebb 400 sprint lehet.

  • A projektek és feladatok korlátai és határai.

  • A címkék a Project for the Web alkalmazásban jelenleg nem támogatottak.

  • A címkék a projekt első megnyitásakor jönnek létre.

  • Projektenként legfeljebb 10 cél lehet.

  • Minden tevékenység egyszer jelenhet meg a Project Tevékenység célként beállításában.

Hibakezelés

  • A műveletkészletekből generált hibák áttekintéséhez lépjen a Beállítások Integrációs>műveleti készletek ütemezése> elemre.
  • A Projektütemezési szolgáltatás által generált hibák áttekintéséhez lépjen a Beállítások ütemezése integráció>PSS-hibanaplói> lapra.

Erőforrás-hozzárendelési szintvonalak szerkesztése

Az entitást frissítő összes többi projektütemezési API-val ellentétben az erőforrás-hozzárendelési API-t csak egyetlen mező, a msdyn_plannedwork frissítésért felel, kizárólag az msydn_resourceassignment entitásban.

Az adott ütemezési mód:

  • rögzített egységek.
  • A projektnaptár hétfőn, kedden, csütörtökön és pénteken csendes-óceáni idő szerint 9:00 és 17:00 óra között van. (Szerdán nincs munka.)
  • Az erőforrásnaptár hétfőtől péntekig 9:00 és 13:00 (csendes-óceáni idő) között van.

Ez a hozzárendelés egy hétre, négy órára egy napra. Ennek az az oka, hogy az erőforrásnaptár 9:00 és 13:00 óra között van (csendes-óceáni idő szerint), vagyis napi négy órában.

  Feladatok Kezdési dátum Befejező dátum Mennyiség 2022 . 6. 13. 2022. 6. 14. 2022. 6. 15. 2022. 6. 16. 2022. 6. 17.
9-1 dolgozó T1 2022 . 6. 13. 2022. 6. 17. 20 4 4 4 4 4

Például ha azt szeretné, hogy a dolgozó a héten minden nap csak három órát dolgozzon, és az egyéb feladatokra is engedélyezne egy órát.

UpdatedContours minta hasznos adat

[{

"minutes":900.0,

"start":"2022-06-13T00:00:00-07:00",

"end":"2022-06-18T00:00:00-07:00"

}]

Ez a Ütemezés a Frissítési kontúr API futtatása után.

  Feladatok Kezdési dátum Befejező dátum Mennyiség 2022 . 6. 13. 2022. 6. 14. 2022. 6. 15. 2022. 6. 16. 2022. 6. 17.
9-1 dolgozó T1 2022 . 6. 13. 2022. 6. 17. 15 3 3 3 3 3

Mintaforgatókönyv

Ebben az esetben létrehoz egy projektet, egy csapattagot, négy tevékenységet és két erőforrás-hozzárendelést. Ezután frissít egy tevékenységet, frissíti a projektet, frissíti az erőforrás-hozzárendelési eloszlást, töröl egy tevékenységet, töröl egy erőforrás-hozzárendelést, és létrehoz egy tevékenységfüggőséget.

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....");

További minták

#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