Jaa


Projektiaikataulun ohjelmointirajapintojen käyttö toimintojen suorittamiseen aikataulutusentiteeteillä

Koskee: Project Operationsin resurssiin/ei-varastointiin perustuvia skenaarioita, Lite-käyttöönotto - kaupasta proformalaskutukseen.

Aikataulutusentiteetit

Projektiaikataulun ohjelmointirajapintojen avulla voi luoda, päivittää ja poistaa toimintoja aikataulutusentiteettien avulla. Näitä entiteettejä hallitaan verkkopohjaisessa Projectissa aikataulutusytimen kautta. Luonti-, päivitys- ja poisto-operaatioita Aikataulutusentiteettien avulla rajoitettiin aiemmissa Dynamics 365 Project Operations -julkaisuissa.

Seuraavassa taulukossa on täydellinen luettelo Projektiaikataulu -entiteeteistä.

Entiteetin nimi Entiteetin looginen nimi
Project msdyn_project
Projektin tehtävä msdyn_projecttask
Projektitehtävän riippuvuus msdyn_projecttaskdependency
Resurssien delegointi msdyn_resourceassignment
Projektin joukko msdyn_projectbucket
Projektiryhmän jäsen msdyn_projectteam
Projektin tarkistusluettelot msdyn_projectchecklist
Projektin selite msdyn_projectlabel
Projektitehtävä, jolle annetaan selite msdyn_projecttasktolabel
Projektisprintti msdyn_projectsprint

OperationSet

OperationSet on työyksikkörakenne, jota voidaan käyttää, kun useita aikatauluihin vaikuttavia pyyntöjä on käsiteltävä tapahtumassa.

Projektiaikataulujen ohjelmointirajapinnat

Seuraavassa on luettelo nykyisistä Projektiaikataulun ohjelmointirajapinnoista.

Ohjelmointirajapinta Description
msdyn_CreateProjectV1 Tätä ohjelmointirajapintaa käytetään projektin luomiseen. Projekti ja oletusprojektisäilö luodaan heti. Projektin luonti voidaan tehdä myös lisäämällä projektitaulukkoon rivi Dataversen vakio-ohjelmointirajapintojen avulla. Tämä prosessi ei luo projektille oletussäilöä, mutta se voi parantaa suorituskykyä.
msdyn_CreateTeamMemberV1 Tätä ohjelmointirajapintaa käytetään projektin ryhmän jäsenen luomiseen. Ryhmän jäsentietue luodaan heti. Ryhmän jäsenen luonti voidaan tehdä myös lisäämällä projektiryhmän jäsentaulukkoon rivi Dataversen vakio-ohjelmointirajapintojen avulla.
msdyn_CreateOperationSetV1 Tämän ohjelmointirajapinnan avulla voidaan aikatauluttaa useita pyyntöjä, jotka on suoritettava tapahtumassa.
msdyn_PssCreateV1 Tätä ohjelmointirajapintaa käytetään entiteetin luomiseen. Entiteetti voi olla mikä tahansa luontitoimintoa tukeva projektin aikataulutusentiteetti.
msdyn_PssCreateV2 Tätä ohjelmointirajapintaa käytetään entiteetin luomiseen. Se toimii samoin kuin msdyn_PssCreateV1, mutta yhdellä toiminnolla voidaan luoda useita entiteettejä.
msdyn_PssUpdateV1 Tätä ohjelmointirajapintaa käytetään entiteetin päivittämiseen. Entiteetti voi olla mikä tahansa päivitystoimintoa tukeva projektin aikataulutusentiteetti.
msdyn_PssUpdateV2 Tätä ohjelmointirajapintaa käytetään entiteettien päivittämiseen. Se toimii samoin kuin msdyn_PssUpdateV1, mutta yhdellä toiminnolla voidaan päivittää useita entiteettejä.
msdyn_PssDeleteV1 Tätä ohjelmointirajapintaa käytetään entiteetin poistamiseen. Entiteetti voi olla mikä tahansa poistotoimintoa tukeva projektin aikataulutusentiteetti.
msdyn_PssDeleteV2 Tätä ohjelmointirajapintaa käytetään entiteettien poistamiseen. Se toimii samoin kuin msdyn_PssDeleteV1, mutta yhdellä toiminnolla voidaan poistaa useita entiteettejä.
msdyn_ExecuteOperationSetV1 Tämän ohjelmointirajapinnan avulla suoritetaan kaikki toiminnot tietyn toimintojoukon sisällä.
msdyn_PssUpdateResourceAssignmentV1 Tätä ohjelmointirajapintaa käytetään päivittämään resurssin määrityksen suunnitellut työt.

Projektiaikataulun ohjelmointirajapintojen käyttäminen OperationSetin kanssa

Koska tietueet luodaan heti sekä CreateProjectV1 - että CreateTeamMemberV1 -toiminnolla, näitä ohjelmointirajapointoja ei voi käyttää suoraan OperationSet -toiminnossa. Niiden avulla voit kuitenkin luoda tarvittavat tietueet, luoda OperationSetin, ja käyttää sitten näitä aiemmin luotuja tietueita OperationSetissä.

Tuetut toiminnot

Aikataulutusentiteetti Luo Update Delete Tärkeitä huomioon otettavia seikkoja
Projektitehtävä Kyllä Kyllä Kyllä Progress-, EffortCompleted- ja EffortRemaining-kenttiä voi muokata Project for the Webissä, mutta niitä ei voi muokata Project Operationsissa.
Projektitehtävän riippuvuus Kyllä No Kyllä Projektitehtävän riippuvuustietueita ei päivitetä. Sen sijaan voidaan poistaa vanha tietue ja luoda uusi tietue.
Resurssien delegointi Kyllä Kyllä* Kyllä Toimintoja, joilla on seuraavat kentät, ei tueta: BookableResourceID, Effort, EffortCompleted, EffortRemaining ja PlannedWork.
Projektin säilö Kyllä Kyllä Kyllä Oletussäilö luodaan CreateProjectV1-ohjelmointirajapinnan avulla. Update Release 16 -versiossa lisättiin projektisäilöjen luonti- ja poistotuki.
Projektiryhmän jäsen Kyllä Kyllä Kyllä Käytä luontioperaatiolle CreateTeamMemberV1 -ohjelmointirajapintaa.
Project Kyllä Kyllä No Toimintoja, joilla on seuraavat kentät, ei tueta StateCode, BulkGenerationStatus, GlobalRevisionToken, CalendarID, Effort, EffortCompleted, EffortRemaining, Progress, Finish, TaskEarliestStart ja Duration.
Projektin tarkistusluettelot Kyllä Kyllä Kyllä
Projektin selite No Kyllä No Selitteiden nimiä voi muuttaa. Tämä toiminto on käytettävissä vain Project for the Webissä. Otsikot luodaan, kun avaat projektin ensimmäisen kerran.
Projektitehtävä, jolle annetaan selite Kyllä No Kyllä Tämä toiminto on käytettävissä vain Project for the Webissä.
Projektisprintti Kyllä Kyllä Kyllä Aloitus-kentässä on oltava Päättymispäivä-kenttää vanhempi päivämäärä. Saman projektin sprintit eivät voi olla päällekkäisiä toistensa kanssa. Tämä toiminto on käytettävissä vain Project for the Webissä.
Projektitavoite Kyllä Kyllä Kyllä Seuraavia kenttiä sisältäviä toimintoja ei tueta: DescriptionPlainText, TaskDisplayOrder
Projektitehtävä, jolle annetaan tavoite Kyllä Ei Kyllä Seuraavia kenttiä sisältäviä toimintoja ei tueta: TaskDisplayOrder

* Resurssien määritystietueita ei päivitetä. Sen sijaan voidaan poistaa vanha tietue ja luoda uusi tietue. Resurssin delegoinnin jaksojen päivittämistä varten on erillinen ohjelmointirajapinta.

Tunnusominaisuus on valinnainen. Jos tunnusominaisuus on annettu, järjestelmä yrittää käyttää sitä ja antaa poikkeuksen, jos sitä ei voi käyttää. Jos sitä ei ole annettu, järjestelmä luo sen.

Rajoitukset ja tunnetut ongelmat

Seuraavassa on luettelo rajoituksista ja tunnetuista ongelmista:

  • Projektiaikataulun ohjelmointirajapintoja voivat käyttää vain käyttäjät, joilla on Microsoft Project -lisenssi. Niitä eivät voi käyttää:

    • Sovelluksen käyttäjät
    • Järjestelmäkäyttäjät
    • Integrointikäyttäjät
    • Muut käyttäjät, joilla ei ole tarvittavaa lisenssiä
  • Kussakin OperationSetissä voi olla enintään 200 toimintoa.

  • Kullakin käyttäjällä voi olla enintään 10 avointa OperationSetiä.

  • Kukin päivitysresurssien määritystoiminto lasketaan yhdeksi toiminnoksi.

  • Kussakin päivitetyssä luettelossa voi olla enintään 100 aikaviipaletta.

  • OperationSet-virheen tila- ja virhelokit eivät ole tällä hetkellä käytettävissä.

  • Projektissa voi olla enintään 400 sprinttiä.

  • Projektien ja tehtävien rajoitukset ja rajat.

Virheen käsittely

  • Voit tarkastella toimintojoukoista luotuja virheitä kohdassa Asetukset>Aikatauluta integrointi>Toimintojoukot.
  • Voit tarkastella Projektin aikataulupalvelussa luotuja virheitä valitsemalla Asetukset>Aikataulun integrointi>PSS-virhelokit.

Resurssien määrityksen jaksotuksen muokkaaminen

Toisin kuin kaikki muut entiteettiä päivittävät projektin aikataulutuksen ohjelmointirajapinnat, resurssin määrityksen ohjelmointirajapinta vastaa yksin yhteen kenttään tehtävistä päivityksistä, msdyn_plannedwork, yksittäisessä entiteetissä, msydn_resourceassignment.

Annettu aikataulutila on:

  • kiinteät yksiköt.
  • Projektin kalenteri on maanantaisin, tiistaisin, torstaisin ja perjantaisin klo 9–17 (Tyynenmeren aika). (Keskiviikkoisin ei ole töitä.)
  • Resurssikalenteri on maanantaista perjantaihin klo 9–13 (Tyynenmeren aika).

Tämä varaus on yksi viikko ja neljä tuntia päivässä, koska resurssin kalenteri on klo 9.00–13.00 (Tyynenmeren aikaa) tai neljä tuntia päivässä.

  Tehtävä Aloituspäivämäärä Päättymispäivämäärä Määrä 6/13/2022 6/14/2022 6/15/2022 6/16/2022 6/17/2022
9-1-työntekijä T1 6/13/2022 6/17/2022 20 4 4 4 4 4

Jos esimerkiksi haluat, että työntekijä työskentelee vain kolme tuntia joka päivä tällä viikolla ja sallitaan tunti muita tehtäviä varten.

UpdatedContours-näytehyötykuorma

[{

"minutes":900.0,

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

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

}]

Tämä on tehtävä Päivitä aikataulu -ohjelmointirajapinnan suorituksen jälkeen.

  Tehtävä Aloituspäivämäärä Päättymispäivämäärä Määrä 6/13/2022 6/14/2022 6/15/2022 6/16/2022 6/17/2022
9-1-työntekijä T1 6/13/2022 6/17/2022 15 3 3 3 3 3

Näyteskenaario

Tässä skenaariossa luodaan projekti, ryhmän jäsen, neljä tehtävää ja kaksi resurssivarausta. Seuraavaksi päivität yhden tehtävän, päivität projektin, päivität resurssimäärityksen aikavälin, poistat yhden tehtävän, poistat yhden resurssin määrityksen ja luot tehtävän riippuvuuden.

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

Muita näytteitä

#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