Share via


Projekto grafiko API sąsajų naudojimas operacijoms su planavimo objektais atlikti

Taikoma: "Project Operations", skirta ištekliais / ne atsargomis pagrįstiems scenarijams, "Lite" diegimas - sandoris su proforma sąskaitų faktūrų išrašymu.

Planavimo objektai

Projekto grafiko API suteikia galimybę atlikti kūrimo, naujinimo ir naikinimo operacijas naudojant planavimo objektus. Šie objektai valdomi naudojant „Project for the Web“ planavimo variklį. Kurti, naujinti ir naikinti operacijas su planavimo objektais buvo apribota ankstesniuose Dynamics 365 Project Operations leidimuose.

Toliau esančioje lentelėje pateikiamas visas projekto grafiko objektų sąrašas.

Objekto pavadinimas Loginis objekto pavadinimas
Project msdyn_project
Projekto užduotis msdyn_projecttask
Projekto užduoties priklausomybė msdyn_projecttaskdependency
Išteklių priskyrimas msdyn_resourceassignment
Projekto talpykla msdyn_projectbucket
Projekto komandos narys msdyn_projectteam
Projekto kontroliniai sąrašai msdyn_projectchecklist
Projekto žyma msdyn_projectlabel
Projekto užduotis, skirta žymėti msdyn_projecttasktolabel
Projekto sprintas msdyn_projectsprint

"OperationSet"

OperationSet yra darbo vieneto modelis, kurį galima naudoti, kai operacijoje reikia apdoroti keletą grafikui poveikį darančių užklausų.

Projekto grafiko API

Toliau pateikiamas dabartinių projekto grafiko API sąrašas.

API Aprašą
msdyn_CreateProjectV1 Šis API yra naudojamas sukurti projektą. Projektas ir numatytoji projekto talpykla yra sukuriami nedelsiant. Projekto kūrimą taip pat galima atlikti pridedant eilutę prie projekto lentelės naudojant standartines Dataverse API. Šis procesas nesukurs numatytojo projekto segmento, bet gali turėti geresnį našumą.
msdyn_CreateTeamMemberV1 Šis API yra naudojamas sukurti projekto komandos narį. Komandos nario įrašas sukuriamas nedelsiant. Komandos narį taip pat galima sukurti įtraukiant eilutę į projekto komandos nario lentelę naudojant standartines Dataverse API.
msdyn_CreateOperationSetV1 Šį API galima naudoti norint suplanuoti keletą užklausų, kurias reikia atlikti operacijoje.
msdyn_PssCreateV1 Šis API yra naudojamas sukurti objektą. Toks objektas gali būti bet kuris projekto planavimo objektas, kuris palaiko kūrimo operaciją.
msdyn_PssCreateV2 Šis API yra naudojamas sukurti objektą. Jis veikia kaip msdyn_PssCreateV1, tačiau vienu veiksmu galima sukurti kelis objektus.
msdyn_PssUpdateV1 Šis API yra naudojamas atnaujinti objektą. Toks objektas gali būti bet kuris projekto planavimo objektas, kuris palaiko naujinimo operaciją.
msdyn_PssUpdateV2 Ši API naudojama atnaujintiems objektams. Jis veikia kaip msdyn_PssUpdateV1, tačiau vienu veiksmu galima atnaujinti kelis objektus.
msdyn_PssDeleteV1 Šis API yra naudojamas panaikinti objektą. Toks objektas gali būti bet kuris projekto planavimo objektas, kuris palaiko naikinimo operaciją.
msdyn_PssDeleteV2 Ši API naudojama objektams naikinti. Jis veikia kaip msdyn_PssDeleteV1, tačiau vienu veiksmu galima ištrinti kelis objektus.
msdyn_ExecuteOperationSetV1 Šis API naudojamas norint vykdyti visas nurodyto operacijų rinkinio operacijas.
msdyn_PssUpdateResourceAssignmentV1 Šis API naudojamas išteklių priskyrimo suplanuoto darbo susiejinimui naujinti.

"Project" grafiko API naudojimas su "OperationSet"

Kadangi įrašai sukuriami iš karto ir "CreateProjectV1 ", ir "CreateTeamMemberV1", šių API negalima tiesiogiai naudoti "OperationSet". Tačiau galite juos naudoti norėdami sukurti reikiamus įrašus, sukurti OperationSet ir tada naudoti iš anksto sukurtus įrašus OperationSet.

Palaikomos operacijos

Grafiko objektas Kūrimas Atnaujinimas Delete Svarbi informacija
Projekto užduotis Taip Taip Taip Laukus Progress, EffortComplete ir EffortRemaining galima redaguoti naudojant "Project for the Web", bet jų negalima redaguoti naudojant "Project Operations".
Projekto užduoties priklausomybė Taip No Taip Projekto užduoties priklausomybės įrašai neatnaujinami. Vietoj to, seną įrašą galima panaikinti ir sukurti naują.
Išteklių priskyrimas Taip Taip* Taip Nepalaikomos operacijos su šiais laukais: BookableResourceID,Effort,EffortCompleted,EffortRemaining ir PlannedWork.
Projekto talpykla Taip Taip Taip Numatytasis segmentas sukuriamas naudojant CreateProjectV1 API. Projektų naikinimo ir kūrimo palaikymas buvo įtrauktas į 16 naujinimo leidimą.
Projekto komandos narys Taip Taip Taip Kūrimo operacijai naudokite "CreateTeamMemberV1 " API.
Project Taip Taip Nepalaikomos operacijos su šiais laukais: StateCode,BulkGenerationStatus,GlobalRevisionToken,CalendarID,Effort,EffortCompleted,EffortRemaining,Progress,Finish,TaskEarlytiestStart ir Duration.
Projekto kontroliniai sąrašai Taip Taip Taip
Projekto žyma No Taip No Žymų pavadinimus galima keisti. Ši funkcija galima tik naudojant "Project", skirtą žiniatinkliui. Etiketės sukuriamos pirmą kartą atidarius projektą.
Projekto užduotis, skirta žymėti Taip No Taip Ši funkcija galima tik naudojant "Project", skirtą žiniatinkliui.
Projekto sprintas Taip Taip Taip Pradžios lauko data turi būti ankstesnė nei lauko Baigti . To paties projekto sprintai negali persidengti. Ši funkcija galima tik naudojant "Project", skirtą žiniatinkliui.
Projekto tikslas Taip Taip Taip Nepalaikomos operacijos su šiais laukais: DescriptionPlainText, TaskDisplayOrder
Projekto užduotis, skirta tikslui Taip No Taip Nepalaikomos operacijos su šiais laukais: TaskDisplayOrder

* Išteklių priskyrimo įrašai neatnaujinami. Vietoj to, seną įrašą galima panaikinti ir sukurti naują. Siekiant atnaujinti išteklių priskyrimo kontūrus, buvo pateikta atskira API.

ID ypatybė yra pasirinktinė. Jei jis pateikiamas, sistema bando jį naudoti ir pateikia išimtį, jei jo negalima naudoti. Jei jis nepateikiamas, sistema jį sugeneruoja.

Apribojimai ir žinomos problemos

Toliau pateikiamas apribojimų ir žinomų problemų sąrašas.

  • "Project" grafiko API gali naudoti tik vartotojai, turintys "Microsoft Project" licenciją. Jų negali toliau nurodyti vartotojai.

    • Programų vartotojai
    • Sistemos vartotojai
    • Integravimo vartotojai
    • Kiti vartotojai, neturintys reikiamos licencijos
  • Kiekviename OperationSet gali būti ne daugiau kaip 200 operacijų.

  • Kiekvienas vartotojas gali turėti ne daugiau kaip 10 atidarytų operacijų rinkinių.

  • „Project Operations“ šiuo metu palaikoma ne daugiau kaip 1000 projekto užduočių iš viso.

  • Kiekviena išteklių priskyrimo naujinimo operacija apskaičiuojama kaip viena operacija.

  • Kiekviename atnaujintų kontūrų sąraše gali būti ne daugiau kaip 100 laiko pjūvių.

  • OperationSet trikties būsenos ir gedimų žurnalai šiuo metu nepasiekiami.

  • Viename projekte yra ne daugiau kaip 400 sprintų.

  • Projektų ir užduočių apribojimai ir ribos.

  • Žymos kol kas pasiekiamos tik „Project for the Web“.

  • Etiketės sukuriamos pirmą kartą atidarius projektą.

  • Viename projekte yra ne daugiau kaip 10 tikslų.

  • Kiekviena užduotis gali būti rodoma projekto užduotyje į tikslą vieną kartą.

Klaidų tvarkymas

  • Norėdami peržiūrėti klaidas, sugeneruotas iš operacijų rinkinių, eikite į Parametrai Planuoti>integravimo>operacijų rinkinius.
  • Norėdami peržiūrėti klaidas, sugeneruotas naudojant projekto grafiko tarnybą, eikite į Parametrų>tvarkaraščio integravimo>PSS klaidų žurnalai.

Išteklių priskyrimo kontūrų redagavimas

Skirtingai nei visos kitos projekto planavimo API, atnaujinančios objektą, išteklių priskyrimo API yra visiškai atsakinga už vieno lauko msdyn_plannedwork, t. y. vieno objekto, msydn_resourceassignment.

Nurodytas grafiko režimas yra:

  • fiksuotų vienetų.
  • Projekto kalendorius yra nuo 9:00 iki 17:00 (Ramiojo vandenyno laiku) pirmadienį, antradienį, ketvirtadienį ir penktadienį. (Trečiadieniais nėra darbo.)
  • Išteklių kalendorius yra nuo 9:00 iki 13:00 (Ramiojo vandenyno laiku) nuo pirmadienio iki penktadienio.

Šis priskyrimas skirtas savaitei, keturioms valandoms per dieną. Taip yra todėl, kad išteklių kalendorius yra nuo 9:00 iki 13:00 (Ramiojo vandenyno laiku) arba keturias valandas per dieną.

  Užduotis Pradžios data Pabaigos data Kiekis 2022-06-13 2022-06-14 2022-06-15 2022-06-16 2022-06-17
9–1 darbuotojai T1 2022-06-13 2022-06-17 20 4 4 4 4 4

Pavyzdžiui, jei norite, kad darbuotojas dirbtų tik tris valandas kiekvieną šios savaitės dieną ir leisti vieną valandą atlikti kitas užduotis.

"UpdatedContours" naudingosios apkrovos pavyzdys

[{

"minutes":900.0,

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

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

}]

Tai yra priskyrimas paleidus grafiko API kontūro naujinimą.

  Užduotis Pradžios data Pabaigos data Kiekis 2022-06-13 2022-06-14 2022-06-15 2022-06-16 2022-06-17
9–1 darbuotojai T1 2022-06-13 2022-06-17 15 3 3 3 3 3

Scenarijaus pavyzdys

Tokiu atveju sukuriate projektą, komandos narį, keturias užduotis ir du išteklių priskyrimus. Tada atnaujinkite vieną užduotį, atnaujinkite projektą, atnaujinkite išteklių priskyrimo kontūrą, panaikinkite vieną užduotį, panaikinkite vieną išteklių priskyrimą ir sukurkite užduoties priklausomybę.

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

Papildomi mėginiai

#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