[Canonical page](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/assignment-update/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# AssignmentUpdate

A partial edit of one existing assignment, matched by its id. Create one with `AssignmentUpdate::new`, set the fields to change, and pass it in [`SchedulingChanges::assignments`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/scheduling-changes.md>) `.update` to [`Project::apply`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#apply>).

## Declaration

```rust
#[derive(Clone, Debug)]
pub struct AssignmentUpdate {
    pub id: Id,
    pub task: Patch<Id>,
    pub resource: Patch<Id>,
    pub value: Patch<f64>,
    pub offset: Patch<f64>,
    pub duration: Patch<f64>,
}
```

## Constructors

### AssignmentUpdate::new

```rust
pub fn new(id: impl Into<Id>) -> AssignmentUpdate
```

Creates an update for the assignment with this id. Every other field starts at [`Patch::Missing`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/patch.md>), so the update changes nothing until a field is set.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `id` | `impl Into<`[`Id`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/id.md>)`>` | Id of the assignment to edit. |

**Returns** an `AssignmentUpdate` with only `id` set.

## Fields

Every field except `id` is a [`Patch`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/patch.md>). Each field maps to the [`AssignmentData`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/assignment-data.md>) field of the same name, which describes how the value is read.

| Field | Type | `Patch::Null` |
|---|---|---|
| `id` | [`Id`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/id.md>) | not a patch |
| `task` | `Patch<`[`Id`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/id.md>)`>` | rejected (required field) |
| `resource` | `Patch<`[`Id`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/id.md>)`>` | rejected (required field) |
| `value` | `Patch<f64>` | rejected (required field) |
| `offset` | `Patch<f64>` | clears it: the slice starts at the task start |
| `duration` | `Patch<f64>` | clears it: the slice runs to the task end |

### id

```rust
pub id: Id
```

Id of the assignment to edit. It must match the `id` of an assignment already in the project. The id itself can't be changed.

### task

```rust
pub task: Patch<Id>
```

Moves the assignment to another task. The new id must name a task in the project.

### resource

```rust
pub resource: Patch<Id>
```

Hands the assignment to another resource. The new id must name a resource in the project.

### value

```rust
pub value: Patch<f64>
```

New utilization rate. Must be finite and greater than `0`.

### offset

```rust
pub offset: Patch<f64>
```

New start of the slice, as worked time from the task start. Must be finite and `>= 0`. `Patch::Null` clears it, which is the same as `0`.

### duration

```rust
pub duration: Patch<f64>
```

New amount of worked time the slice books. Must be finite and greater than `0`. `Patch::Null` clears it, so the slice runs to the task end.

Changes to `offset` and `duration` never move task dates. Changes to `task` and `resource` move dates only when a task ends up working on other calendars; see [Resources and assignments](<https://docs.dhtmlx.com/planning-engine/rust/resources-and-assignment/resources-and-assignments.md>).

## Errors

[`Project::apply`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#apply>) lists a rejected update in [`ApplyReport::rejected`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/apply-report.md#rejected>) at the path `assignments.update[i]`. An update is rejected when:

- no assignment has this `id`
- `task`, `resource` or `value` is [`Patch::Null`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/patch.md>)
- `task` or `resource` names an id that isn't in the project
- `value`, `offset` or `duration` is out of the range given for that field above
- in [`CalendarMode::Resource`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/calendar-mode.md>), the task's calendar and the resource's calendar share no weekly working time

## Example

Hand the second half of a 4-day task from `anna` to `ben`: `anna` keeps the first 2 days of work, and `ben`'s assignment moves to start after them and run to the task end.

```rust
use plen_core::{
    AssignmentData, AssignmentUpdate, DateTime, Patch, Project, ProjectData, ResourceData,
    SchedulingChanges, SolveOptions, TaskData,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let start = DateTime::from_ymd_hm(2026, 4, 6, 8, 0).ok_or("invalid date")?;

    let data = ProjectData {
        tasks: vec![TaskData {
            start_date: Some(start),
            duration: Some(4.0),
            ..TaskData::new("build")
        }],
        resources: vec![
            ResourceData { id: "anna".into(), capacity: None, calendar_id: None },
            ResourceData { id: "ben".into(), capacity: None, calendar_id: None },
        ],
        assignments: vec![
            AssignmentData {
                id: Some("build:anna".into()),
                task: "build".into(),
                resource: "anna".into(),
                value: 1.0,
                offset: None,
                duration: None,
            },
            AssignmentData {
                id: Some("build:ben".into()),
                task: "build".into(),
                resource: "ben".into(),
                value: 1.0,
                offset: None,
                duration: None,
            },
        ],
        ..Default::default()
    };

    let mut project = Project::default();
    project.solve(Some(data), &SolveOptions::default())?;

    let mut anna = AssignmentUpdate::new("build:anna");
    anna.duration = Patch::Value(2.0);

    let mut ben = AssignmentUpdate::new("build:ben");
    ben.offset = Patch::Value(2.0);
    ben.duration = Patch::Null;

    let mut changes = SchedulingChanges::default();
    changes.assignments.update = vec![anna, ben];

    let report = project.apply(&changes)?;
    assert!(report.rejected.is_empty());
    Ok(())
}
```

## Related

- [`AssignmentData`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/assignment-data.md>) - the record an update edits
- [`Patch`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/patch.md>) - the type of every editable field
- [`ApplyReport`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/apply-report.md>) - reports whether the update was applied
- [Split assignment work](<https://docs.dhtmlx.com/planning-engine/rust/how-to/split-assignment-work.md>) - uses `offset` and `duration` updates to hand work over
- [Data Updates](<https://docs.dhtmlx.com/planning-engine/rust/live-projects/editing-a-project.md>) - shows update records in a change set
