Menggunakan API jadwal proyek untuk melakukan operasi dengan entitas Penjadwalan

Berlaku untuk: Project Operations Terintegrasi dengan ERP, Project Operations Core.

Menjadwalkan entitas

API jadwal proyek menyediakan kemampuan untuk membuat, memperbarui, dan menghapus entitas Penjadwalan. Mesin Penjadwalan di Project untuk web mengelola entitas ini. Rilis Dynamics 365 Project Operations sebelumnya membatasi operasi pembuatan, pembaruan, dan penghapusan untuk entitas Scheduling.

Tabel berikut menyediakan daftar lengkap entitas jadwal Proyek.

Nama entitas Nama logika entitas
Proyek msdyn_project
Tugas Proyek msdyn_projecttask
Dependensi Tugas Proyek msdyn_projecttaskdependency
Penetapan Sumber Daya msdyn_resourceassignment
Wadah Proyek msdyn_projectbucket
Anggota Tim Proyek msdyn_projectteam
Daftar Periksa Proyek msdyn_projectchecklist
Label Proyek msdyn_projectlabel
Tugas Proyek yang akan Dilabeli msdyn_projecttasktolabel
Sprint Proyek msdyn_projectsprint

OperationSet

Gunakan OperationSet sebagai unit kerja saat Anda perlu memproses beberapa permintaan yang memengaruhi jadwal dalam transaksi.

API jadwal proyek

Daftar berikut menunjukkan API jadwal Project saat ini.

API Deskripsi
msdyn_CreateProjectV1 Gunakan API ini untuk membuat project. Ini segera membuat proyek dan bucket proyek default. Anda juga dapat membuat proyek dengan menambahkan baris ke tabel proyek dengan menggunakan API Dataverse standar. Proses ini tidak membuat bucket default untuk proyek tetapi mungkin memiliki performa yang lebih baik.
msdyn_CreateTeamMemberV1 Gunakan API ini untuk membuat anggota tim proyek. Ini segera membuat catatan anggota tim. Anda juga dapat membuat anggota tim dengan menambahkan baris ke tabel Anggota Tim Proyek dengan menggunakan API Dataverse standar.
msdyn_CreateOperationSetV1 Gunakan API ini untuk menjadwalkan beberapa permintaan yang harus dilakukan dalam transaksi.
msdyn_PssCreateV1 Gunakan API ini untuk membuat entitas. Entitas dapat merupakan entitas penjadwalan Proyek yang mendukung operasi pembuatan.
msdyn_PssCreateV2 Gunakan API ini untuk membuat entitas. Ini berfungsi seperti msdyn_PssCreateV1, tetapi Anda dapat membuat beberapa entitas dalam satu tindakan.
msdyn_PssUpdateV1 Gunakan API ini untuk memperbarui entitas. Entitas dapat merupakan entitas penjadwalan Proyek yang mendukung operasi pembaruan.
msdyn_PssUpdateV2 Gunakan API ini untuk memperbarui entitas. Ini berfungsi seperti msdyn_PssUpdateV1, tetapi Anda dapat memperbarui beberapa entitas dalam satu tindakan.
msdyn_PssDeleteV1 Gunakan API ini untuk menghapus entitas. Entitas dapat merupakan entitas penjadwalan Proyek yang mendukung operasi penghapusan.
msdyn_PssDeleteV2 Gunakan API ini untuk menghapus entitas. Ini berfungsi seperti msdyn_PssDeleteV1, tetapi Anda dapat menghapus beberapa entitas dalam satu tindakan.
msdyn_ExecuteOperationSetV1 Gunakan API ini untuk menjalankan semua operasi dalam kumpulan operasi yang diberikan.
msdyn_PssUpdateResourceAssignmentV1 Gunakan API ini untuk memperbarui kontur kerja yang direncanakan Penetapan Sumber Daya.

Menggunakan API jadwal Project dengan OperationSet

Karena CreateProjectV1 dan CreateTeamMemberV1 segera membuat rekaman, Anda tidak dapat menggunakan API ini secara langsung di OperationSet. Namun, Anda dapat menggunakan API ini untuk membuat rekaman yang diperlukan, membuat OperationSet, lalu menggunakan rekaman yang telah dibuat sebelumnya di OperationSet.

Operasi yang Didukung

Entitas Penjadwalan Create Update Delete Pertimbangan penting
Tugas proyek Yes Yes Yes Anda dapat mengedit bidang EffortCompleted dan EffortRemaining di Project untuk Web, tetapi Anda tidak dapat mengedit bidang ini di Project Operations.
Dependensi Tugas Proyek Yes No Yes Rekaman dependensi tugas proyek tidak diperbarui. Sebagai gantinya, Anda dapat menghapus rekaman lama dan membuat rekaman baru.
Penugasan Sumber Daya Yes Ya* Yes Operasi dengan bidang berikut tidak didukung: BookableResourceID,Upaya,UpayaSelesai,UpayaRemaining, dan PlannedWork.
Wadah Proyek Yes Yes Yes Wadah default dibuat dengan menggunakan API CreateProjectV1 . Dukungan untuk membuat dan menghapus wadah proyek telah ditambahkan dalam Pembaruan Release 16.
Anggota Tim Proyek Yes Yes Yes Untuk operasi buat, gunakan API CreateTeamMemberV1 .
Proyek Yes Yes No Operasi dengan bidang berikut tidak didukung: StateCode,BulkGenerationStatus,GlobalRevisionToken,CalendarID,Upaya,EffortCompleted,EffortRemaining,Progress,Finish,TaskEarliestStart, dan Duration.
Daftar Periksa Proyek Yes Yes Yes
Label Proyek No Yes No Anda dapat mengubah nama label. Fitur ini hanya tersedia untuk Project for the Web. Label dibuat saat pertama kali Anda membuka proyek.
Tugas Proyek yang akan Dilabeli Yes No Yes Fitur ini hanya tersedia untuk Project for the Web.
Sprint Proyek Yes Yes Yes Bidang Mulai harus memiliki tanggal lebih awal dari bidang Selesai. Sprint untuk proyek yang sama tidak dapat tumpang tindih satu sama lain. Fitur ini hanya tersedia untuk Project for the Web.
Sasaran Proyek Yes Yes Yes Operasi dengan bidang berikut tidak didukung: DescriptionPlainText, TaskDisplayOrder
Tugas Proyek untuk Sasaran Yes No Yes Operasi dengan bidang berikut tidak didukung: TaskDisplayOrder

* Rekaman penetapan sumber daya tidak diperbarui. Sebagai gantinya, Anda dapat menghapus catatan lama dan membuat catatan baru. API terpisah disediakan untuk memperbarui kontur Penetapan Sumber Daya.

Properti ID bersifat opsional. Jika Anda memberikan properti ID, sistem mencoba menggunakannya dan melemparkan pengecualian jika tidak dapat digunakan. Jika Anda tidak memberikan properti ID, sistem akan menghasilkannya.

Keterbatasan dan masalah yang diketahui

Daftar berikut menunjukkan batasan dan masalah yang diketahui:

  • Hanya Pengguna dengan Lisensi Microsoft Project yang dapat menggunakan API Jadwal Proyek. Pengguna berikut tidak dapat menggunakan API ini:

    • Pengguna aplikasi
    • Pengguna Sistem
    • Pengguna Integrasi
    • Pengguna lain yang tidak memiliki lisensi yang diperlukan
  • Setiap OperationSet hanya dapat memiliki hingga 200 operasi.

  • Setiap pengguna hanya dapat memiliki hingga 10 OperationSet terbuka.

  • Setiap operasi Kontur Penetapan Penetapan Sumber Daya Perbarui dihitung sebagai satu operasi.

  • Setiap daftar kontur yang diperbarui dapat berisi hingga 100 irisan waktu.

  • Status kegagalan OperationSet dan log kegagalan saat ini tidak tersedia.

  • Setiap proyek dapat memiliki hingga 400 sprint.

  • Batasan dan batasan pada proyek dan tugas.

Penanganan kesalahan

  • Untuk meninjau kesalahan yang dihasilkan dari Set Operasi, buka Pengaturan Jadwalkan>Set Operasi> Integrasi.
  • Untuk meninjau kesalahan yang dihasilkan dari Layanan jadwal proyek, buka Log Kesalahan> PSS Integrasi>Jadwal Pengaturan.

Mengedit kontur penetapan sumber daya

Tidak seperti semua API penjadwalan proyek lainnya yang memperbarui entitas, API kontur penetapan sumber daya hanya memperbarui satu bidang, msdyn_plannedwork, pada satu entitas, msydn_resourceassignment.

Mode jadwal yang ditentukan adalah:

  • unit tetap.
  • Kalender proyek adalah dari pukul 09:00 hingga 17:00 (Waktu Pasifik) Senin, Selasa, Kamis, dan Jumat. (Tidak ada pekerjaan pada hari Rabu.)
  • Kalender sumber daya adalah dari pukul 09.00 hingga 1.00 (Waktu Pasifik) Senin hingga Jumat.

Penugasan ini selama satu minggu, empat jam sehari karena kalender sumber daya adalah dari pukul 09.00 hingga 1.00 (Waktu Pasifik), atau empat jam sehari.

  Tugas Tanggal Mulai Tanggal Selesai Kuantitas 13/6/2022 14/6/2022 15/6/2022 16/6/2022 17/6/2022
Pekerja 9-1 T1 13/6/2022 17/6/2022 20 4 4 4 4 4

Misalnya, jika Anda ingin agar pekerja hanya bekerja tiga jam setiap hari di minggu ini dan memungkinkan selama satu jam untuk tugas lainnya.

Muatan sampel UpdateContours

[{

"minutes":900.0,

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

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

}]

Penetapan ini dilakukan setelah API Jadwal Kontur Perbarui berjalan.

  Tugas Tanggal Mulai Tanggal Selesai Kuantitas 13/6/2022 14/6/2022 15/6/2022 16/6/2022 17/6/2022
Pekerja 9-1 T1 13/6/2022 17/6/2022 15 3 3 3 3 3

Contoh skenario

Dalam skenario ini, Anda membuat proyek, anggota tim, empat tugas, dan dua penugasan sumber daya. Selanjutnya, Anda memperbarui satu tugas, memperbarui proyek, memperbarui kontur penetapan sumber daya, menghapus satu tugas, menghapus satu penetapan sumber daya, dan membuat dependensi tugas.

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

Sampel tambahan

#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