AssignmentData#

Books a resource on a task at a utilization rate. An optional slice limits the booking to part of the task's work. Add instances to ProjectData.assignments. Create one with new AssignmentData() and the fluent setters. Assignments added after the first solve go through SchedulingChanges.assignments, and edits go through AssignmentUpdate.

Declaration#

public class AssignmentData extends ValueRecord implements DeepCloneable<AssignmentData>

Constructors#

AssignmentData()#

public AssignmentData()

Creates an assignment with every field at its default. Set task, resource and value before the data reaches the engine.

Fields#

Field Type Default Description
id Id null Assignment ID. null gets a generated string ID ("$generated_assignment_1", "$generated_assignment_2", ...) on import. A generated ID never takes an ID already used by another assignment.
task Id null ID of the assigned task. Required: null throws NullPointerException on import.
resource Id null ID of the booked resource. Required: null throws NullPointerException on import.
value double 0.0 Utilization rate, in the units of ResourceData.capacity: 1.0 = 100 %. Must be finite and greater than 0, so the default 0.0 is rejected.
offset Double null Start of the slice: worked time from the task start, in the task's durationUnit. null means 0.
duration Double null Length of the slice: worked time booked from offset, in the task's durationUnit. null books up to the task end.

Slices#

offset and duration choose which part of the task's work the assignment books. They change resource load only. Task dates never depend on them. Both are measured in worked time on the assignment's calendar, so non-working time and pauses don't count. The slice is clipped to the task's work when load is booked, so it follows a task that gets shorter later. An offset at or past the task's work books nothing. Several assignments of one resource on one task each book their own slice at their own value, and overlapping slices add up.

How the assignment's calendar is picked is covered in Working time and calendars. For a walk-through, see Split assignment work.

Assignments on unscheduled tasks#

An assignment whose task has TaskData.unscheduled set to true is still validated, but it books no load. The result reports it in notes as a Note.DroppedAssignment. The assignment keeps its slice and books it again when the task is scheduled.

Methods#

withId#

public AssignmentData withId(Id value)

Sets id and returns this instance for chaining.

Returns - this AssignmentData.

withTask#

public AssignmentData withTask(Id value)

Sets task and returns this instance for chaining.

Returns - this AssignmentData.

withResource#

public AssignmentData withResource(Id value)

Sets resource and returns this instance for chaining.

Returns - this AssignmentData.

withValue#

public AssignmentData withValue(double value)

Sets value and returns this instance for chaining.

Returns - this AssignmentData.

withOffset#

public AssignmentData withOffset(Double value)

Sets offset and returns this instance for chaining. null clears it.

Returns - this AssignmentData.

withDuration#

public AssignmentData withDuration(Double value)

Sets duration and returns this instance for chaining. null clears it.

Returns - this AssignmentData.

deepClone#

public AssignmentData deepClone()

Returns a copy with the same field values. Every field is immutable (Id) or a value, so the copy is fully independent.

Returns - a new AssignmentData.

copy#

public AssignmentData copy()

Returns a shallow copy. For AssignmentData it is equivalent to deepClone().

Returns - a new AssignmentData with the same field values.

equals, hashCode, toString#

public boolean equals(Object other)
public int hashCode()
public String toString()

Inherited from ValueRecord. Two AssignmentData are equal when all six fields are equal. toString() lists the fields, for logging.

Errors#

The call that receives the data throws InputException with kind InputErrorKind.VALIDATION:

Path When
assignments[i].id Two assignments share an ID. IDs compare by their key, so Id.num(1) and Id.str("1") collide.
assignments[i].value value is not finite or is <= 0.
assignments[i].offset offset is not finite or is < 0.
assignments[i].duration duration is not finite or is <= 0.
assignments[i].resource No resource has this ID.
assignments[i].task No task has this ID.
assignments[i] In CalendarMode.RESOURCE, the task has its own calendar, the resource has a calendar, and the two share no weekly working time.
id An id, task or resource holds a number that isn't finite.

In Validation.REPAIR mode some of these are fixed instead, and each fix is recorded as a Note.Repaired:

  • An invalid offset or duration is cleared to null.
  • With a repeated non-null id, the later assignment replaces the earlier one at the earlier position.

Example#

import java.util.List;
import org.dhtmlx.plen.*;

public class AssignmentDataExample {
  public static void main(String[] args) throws Exception {
    ProjectData data = new ProjectData()
        .withTasks(List.of(
            new TaskData(Id.num(1))
                .withStartDate(Moment.fromYmdHm(2026, 3, 2, 8, 0))
                .withDuration(5.0)))
        .withResources(List.of(new ResourceData().withId(Id.str("ann"))))
        .withAssignments(List.of(
            // Full time for the whole task.
            new AssignmentData()
                .withTask(Id.num(1))
                .withResource(Id.str("ann"))
                .withValue(1.0),
            // Half time on the last day only: days 4 to 5 of the task's work.
            new AssignmentData()
                .withId(Id.str("review"))
                .withTask(Id.num(1))
                .withResource(Id.str("ann"))
                .withValue(0.5)
                .withOffset(4.0)
                .withDuration(1.0)));

    ScheduleResult result = new Project().solve(data, new SolveOptions());
    System.out.println(result.overallocations);
  }
}