Skip to main content

Project

Struct Project 

Source
pub struct Project { /* private fields */ }
Expand description

Represents a project with a name and a list of resources.

Implementations§

Source§

impl Project

Source

pub fn builder() -> ProjectBuilder

Create an instance of Project using the builder syntax

Source§

impl Project

Source

pub fn new(name: impl Into<String>) -> Self

Creates a new project with the given name.

§Arguments
  • name - The name of the project.
§Returns

A new Project instance.

§Example
use planter_core::project::Project;

let project = Project::new("World domination");
assert_eq!(project.name(), "World domination");
Source

pub fn name(&self) -> &str

Returns the name of the project.

§Example
use planter_core::project::Project;

let project = Project::new("World domination");
assert_eq!(project.name(), "World domination");
Source

pub fn description(&self) -> Option<&str>

Returns the description of the project.

§Example
use planter_core::project::Project;

let project = Project::new("World domination");
assert_eq!(project.description(), None);
Source

pub fn add_task(&mut self, task: Task) -> Uuid

Adds a task to the project and returns its stable Uuid.

Adding a task whose id already exists in the project replaces it in place, without duplicating its slot in Self::tasks.

§Arguments
  • task - The task to add to the project.
§Returns

The stable Uuid assigned to the task.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
assert_eq!(project.tasks().count(), 1);
Source

pub fn add_sibling_before( &mut self, task: Task, sibling_id: Uuid, ) -> Result<Uuid>

Inserts a new task as a sibling right before sibling_id in the task order. If the sibling has a parent, the new task becomes a child of the same parent. This only ever inserts a new task, it never moves an existing one.

§Errors

Returns an error if sibling_id doesn’t exist, or if task’s id is already used by another task in the project.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let a = project.add_task(Task::new("Build an army"));
let b = project.add_task(Task::new("Train troops"));
let c = project.add_sibling_before(Task::new("Gather allies"), b).unwrap();

let ids: Vec<_> = project.tasks().map(|t| t.id()).collect();
assert_eq!(ids, vec![a, c, b]);
Source

pub fn add_sibling_after( &mut self, task: Task, sibling_id: Uuid, ) -> Result<Uuid>

Inserts a new task as a sibling right after sibling_id in the task order. If the sibling has a parent, the new task becomes a child of the same parent. This only ever inserts a new task, it never moves an existing one.

§Errors

Returns an error if sibling_id doesn’t exist, or if task’s id is already used by another task in the project.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let a = project.add_task(Task::new("Build an army"));
let b = project.add_task(Task::new("Train troops"));
let c = project.add_sibling_after(Task::new("Gather allies"), a).unwrap();

let ids: Vec<_> = project.tasks().map(|t| t.id()).collect();
assert_eq!(ids, vec![a, c, b]);
Source

pub fn rm_task(&mut self, id: Uuid) -> Result<Task>

Deletes a task and all references to it from the project. Any direct subtasks of the removed task are promoted to the removed task’s own parent (or to top-level, if it had none).

§Arguments
  • id - The Uuid of the task to remove.
§Errors

Returns an error if the task doesn’t exist.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
assert_eq!(project.tasks().count(), 1);
assert!(project.rm_task(id).is_ok());
assert_eq!(project.tasks().count(), 0);
Source

pub fn task(&self, id: Uuid) -> Option<&Task>

Gets a reference to the task with the given Uuid.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
assert_eq!(project.task(id).unwrap().name(), "Become world leader");
Source

pub fn tasks(&self) -> impl Iterator<Item = &Task>

Returns the tasks of the project in insertion order.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
project.add_task(Task::new("Become world leader"));
assert_eq!(project.tasks().count(), 1);
Source

pub fn add_time_relationship( &mut self, predecessor: Uuid, successor: Uuid, kind: TimeRelationship, ) -> Result<()>

Adds a relationship between tasks, where one is the predecessor and the other a successor.

§Arguments
  • predecessor - The Uuid of the predecessor task.
  • successor - The Uuid of the successor task.
  • kind - The type of relationship.
§Errors

Returns an error if either task doesn’t exist, if the relationship already exists, if the relationship would create a cycle, or if one task is a subtask ancestor/descendant of the other.

§Example
use planter_core::{project::{Project, TimeRelationship}, task::Task};

let mut project = Project::new("World domination");
let pred = project.add_task(Task::new("Get rich"));
let succ = project.add_task(Task::new("Become world leader"));
project.add_time_relationship(pred, succ, TimeRelationship::default());

assert_eq!(project.successors(pred).next().unwrap().name(), "Become world leader")
Source

pub fn rm_time_relationship( &mut self, predecessor: Uuid, successor: Uuid, ) -> Result<()>

Removes a relationship between tasks.

§Arguments
  • predecessor - The Uuid of the predecessor task.
  • successor - The Uuid of the successor task.
§Errors

Returns an error if no relationship exists between the tasks.

§Example
use planter_core::{project::{Project, TimeRelationship}, task::Task};

let mut project = Project::new("World domination");
let pred = project.add_task(Task::new("Get rich"));
let succ = project.add_task(Task::new("Become world leader"));
project.add_time_relationship(pred, succ, TimeRelationship::default());
project.rm_time_relationship(pred, succ).unwrap();

assert_eq!(project.successors(pred).count(), 0);
Source

pub fn successors(&self, id: Uuid) -> impl Iterator<Item = &Task>

Gets the successors of a given task.

§Example
use planter_core::{project::{Project, TimeRelationship}, task::Task};

let mut project = Project::new("World domination");
let pred = project.add_task(Task::new("Get rich"));
let succ = project.add_task(Task::new("Become world leader"));
project.add_time_relationship(pred, succ, TimeRelationship::default());

assert_eq!(project.successors(pred).next().unwrap().name(), "Become world leader")
Source

pub fn successors_ids(&self, id: Uuid) -> impl Iterator<Item = Uuid>

Gets the Uuids of all successors for a given task.

§Example
use planter_core::{project::{Project, TimeRelationship}, task::Task};

let mut project = Project::new("World domination");
let pred = project.add_task(Task::new("Get rich"));
let succ = project.add_task(Task::new("Become world leader"));
project.add_time_relationship(pred, succ, TimeRelationship::default());

assert_eq!(project.successors_ids(pred).next().unwrap(), succ)
Source

pub fn predecessors(&self, id: Uuid) -> impl Iterator<Item = &Task>

Gets the predecessors of a given task.

§Example
use planter_core::{project::{Project, TimeRelationship}, task::Task};

let mut project = Project::new("World domination");
let pred = project.add_task(Task::new("Get rich"));
let succ = project.add_task(Task::new("Become world leader"));
project.add_time_relationship(pred, succ, TimeRelationship::default());

assert_eq!(project.predecessors(succ).next().unwrap().name(), "Get rich")
Source

pub fn predecessors_ids(&self, id: Uuid) -> impl Iterator<Item = Uuid>

Gets the Uuids of all predecessors for a given task.

§Example
use planter_core::{project::{Project, TimeRelationship}, task::Task};

let mut project = Project::new("World domination");
let pred = project.add_task(Task::new("Get rich"));
let succ = project.add_task(Task::new("Become world leader"));
project.add_time_relationship(pred, succ, TimeRelationship::default());

assert_eq!(project.predecessors_ids(succ).next().unwrap(), pred)
Source

pub fn update_relationships( &mut self, task_id: Uuid, ids: &[Uuid], dir: RelDir, kind: TimeRelationship, ) -> Result<()>

Sets the predecessors or successors of a task to exactly the given set of tasks.

§Arguments
  • task_id - The Uuid of the task whose relationships need updating.
  • ids - The tasks to set as predecessors or successors.
  • dir - Whether to update predecessors or successors.
  • kind - The type of time relationship.
§Errors

Returns an error if:

  • Any task doesn’t exist.
  • The update would create a cycle.
  • Any id in ids is a subtask ancestor/descendant of task_id.
§Example
use planter_core::{project::{Project, RelDir, TimeRelationship}, task::Task};

let mut project = Project::new("World domination");
let id0 = project.add_task(Task::new("Become world leader"));
let id1 = project.add_task(Task::new("Get rich"));
let id2 = project.add_task(Task::new("Be evil"));

project.update_relationships(id2, &[id0, id1], RelDir::Predecessors, TimeRelationship::FinishToStart).unwrap();
assert_eq!(project.predecessors(id2).count(), 2);
Source

pub fn move_task_after(&mut self, id: Uuid, after_id: Uuid) -> Result<()>

Moves id right after after_id in the global task order, affecting display order.

§Errors

Returns an error if id or after_id doesn’t exist, or if they’re the same task (there’s nothing to move relative to).

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let a = project.add_task(Task::new("Build an army"));
let b = project.add_task(Task::new("Train troops"));
let c = project.add_task(Task::new("Gather allies"));
project.move_task_after(c, a).unwrap();

let ids: Vec<_> = project.tasks().map(|t| t.id()).collect();
assert_eq!(ids, vec![a, c, b]);
Source

pub fn add_subtask(&mut self, parent_id: Uuid, child_id: Uuid) -> Result<()>

Adds a subtask to a given task, marking the child as a component of the parent. The parent task is completed when all children are completed.

§Arguments
  • parent_id - The Uuid of the parent task.
  • child_id - The Uuid of the child subtask.
§Errors

Returns an error if either task doesn’t exist.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let parent = project.add_task(Task::new("Build a house"));
let child1 = project.add_task(Task::new("Lay foundations"));
let child2 = project.add_task(Task::new("Build roof"));

project.add_subtask(parent, child1).unwrap();
project.add_subtask(parent, child2).unwrap();
assert_eq!(project.subtasks(parent).count(), 2);
Source

pub fn remove_subtask(&mut self, child_id: Uuid) -> Result<()>

Removes a subtask relationship, promoting the child back to a top-level task.

§Errors

Returns an error if the task is not a subtask.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let army = project.add_task(Task::new("Build an army"));
let supplies = project.add_task(Task::new("Gather supplies"));
project.add_subtask(army, supplies).unwrap();
assert!(project.task_parent(supplies).is_some());

project.remove_subtask(supplies).unwrap();
assert!(project.task_parent(supplies).is_none());
Source

pub fn task_parent(&self, child_id: Uuid) -> Option<Uuid>

Returns the parent Uuid of a subtask, or None if the task is at root level.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let army = project.add_task(Task::new("Build an army"));
let supplies = project.add_task(Task::new("Gather supplies"));

assert!(project.task_parent(supplies).is_none());

project.add_subtask(army, supplies).unwrap();
assert_eq!(project.task_parent(supplies), Some(army));
Source

pub fn subtasks(&self, parent_id: Uuid) -> impl Iterator<Item = Uuid> + '_

Gets the Uuids of all subtasks of the given task.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let parent = project.add_task(Task::new("Build a house"));
let child = project.add_task(Task::new("Lay foundations"));
assert_eq!(project.subtasks(parent).count(), 0);

project.add_subtask(parent, child).unwrap();
assert_eq!(project.subtasks(parent).count(), 1);
Source

pub fn edit_task_start(&mut self, id: Uuid, start: DateTime<Utc>) -> Result<()>

Sets a task’s start date, then rolls the change up through every ancestor so each one’s own start/finish keeps covering all of its descendants. If the task has a finish date earlier than start, the finish date is pulled forward to match it instead of leaving a negative duration.

§Errors

Returns an error if id doesn’t exist.

§Example
use chrono::Utc;
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let army = project.add_task(Task::new("Build an army"));
let supplies = project.add_task(Task::new("Gather supplies"));
project.add_subtask(army, supplies).unwrap();

let now = Utc::now();
project.edit_task_start(supplies, now).unwrap();

// `army`'s own start followed along automatically, no separate step needed.
assert_eq!(project.task(army).unwrap().start(), Some(now));
Source

pub fn edit_task_finish( &mut self, id: Uuid, finish: DateTime<Utc>, ) -> Result<()>

Sets a task’s finish date, then rolls the change up through every ancestor so each one’s own start/finish keeps covering all of its descendants. If the task has a start date later than finish, the start date is pulled back to match it instead of leaving a negative duration.

§Errors

Returns an error if id doesn’t exist.

§Example
use chrono::Utc;
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let army = project.add_task(Task::new("Build an army"));
let supplies = project.add_task(Task::new("Gather supplies"));
project.add_subtask(army, supplies).unwrap();

let now = Utc::now();
project.edit_task_finish(supplies, now).unwrap();

assert_eq!(project.task(army).unwrap().finish(), Some(now));
Source

pub fn edit_task_duration( &mut self, id: Uuid, duration: NonNegativeDuration, ) -> Result<()>

Sets a task’s duration, then rolls the change up through every ancestor so each one’s own start/finish keeps covering all of its descendants.

§Errors

Returns an error if id doesn’t exist.

§Example
use chrono::Duration;
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let task_id = project.add_task(Task::new("Build an army"));
project.edit_task_duration(task_id, Duration::hours(4).try_into().unwrap()).unwrap();
assert!(project.task(task_id).unwrap().duration().is_some());
Source

pub fn edit_task_name( &mut self, id: Uuid, name: impl Into<String>, ) -> Result<()>

Edits a task’s name.

§Errors

Returns an error if id doesn’t exist.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
project.edit_task_name(id, "Become world's biggest loser").unwrap();
assert_eq!(project.task(id).unwrap().name(), "Become world's biggest loser");
Source

pub fn edit_task_description( &mut self, id: Uuid, description: impl Into<String>, ) -> Result<()>

Edits a task’s description.

§Errors

Returns an error if id doesn’t exist.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
project.edit_task_description(id, "Step one of the plan").unwrap();
assert_eq!(project.task(id).unwrap().description(), Some("Step one of the plan"));
Source

pub fn clear_task_description(&mut self, id: Uuid) -> Result<()>

Clears a task’s description, setting it to None.

§Errors

Returns an error if id doesn’t exist.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
project.edit_task_description(id, "Step one of the plan").unwrap();

project.clear_task_description(id).unwrap();
assert!(project.task(id).unwrap().description().is_none());
Source

pub fn toggle_task_completed(&mut self, id: Uuid) -> Result<()>

Toggles a task’s completed status.

§Errors

Returns an error if id doesn’t exist.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
assert!(!project.task(id).unwrap().completed());

project.toggle_task_completed(id).unwrap();
assert!(project.task(id).unwrap().completed());
Source

pub const fn start_date(&self) -> Option<DateTime<Utc>>

Returns the start date of the project.

§Example
use planter_core::project::Project;
use chrono::Utc;

let start_date = Utc::now();
let project = Project::builder().name("World domination").start_date(start_date).build();
assert_eq!(project.start_date(), Some(start_date));
Source

pub const fn end_date(&self) -> Option<DateTime<Utc>>

Returns the end date of the project.

§Example
use planter_core::project::Project;
use chrono::Utc;

let mut project = Project::new("World domination");
assert!(project.end_date().is_none());
let end_date = Utc::now();
project.set_end_date(end_date);
assert_eq!(project.end_date(), Some(end_date));
Source

pub const fn set_end_date(&mut self, end_date: DateTime<Utc>)

Sets the end date of the project.

§Example
use planter_core::project::Project;
use chrono::Utc;

let mut project = Project::new("World domination");
let end_date = Utc::now();
project.set_end_date(end_date);
assert_eq!(project.end_date(), Some(end_date));
Source

pub fn add_resource(&mut self, resource: Resource) -> Uuid

Adds a resource to the project’s pool and returns its stable Uuid. One-time purchase costs belong on the Resource itself (via Resource::add_purchase), recorded once regardless of how many tasks engage it via Self::assign_resource.

Adding a resource whose id already exists in the pool replaces it in place, without duplicating its slot in Self::resources.

§Arguments
  • resource - The resource to add to the project.
§Example
use planter_core::{resources::Resource, project::Project};

let mut project = Project::new("World domination");
project.add_resource(Resource::new("Stimpack".parse().unwrap()));
assert_eq!(project.resources().count(), 1);
Source

pub fn resource(&self, id: Uuid) -> Option<&Resource>

Get a reference to a resource in the project, by its stable Uuid.

§Example
use planter_core::{resources::Resource, project::Project};

let mut project = Project::new("World domination");
let id = project.add_resource(Resource::new("Stimpack".parse().unwrap()));

assert!(project.resource(id).is_some());
Source

pub fn rm_resource(&mut self, id: Uuid) -> Result<(Resource, Vec<(Uuid, u32)>)>

Remove a resource from the project, by its stable Uuid. Any task assignments that referred to it are dropped too, so no task is left pointing at a resource that no longer exists. The returned (task_id, quantity) pairs record what those were, so a caller that wants to undo the removal can restore them with Self::assign_resource_units.

§Errors

Returns an error if id doesn’t refer to a resource in Self::resources.

§Example
use planter_core::{resources::Resource, project::Project};

let mut project = Project::new("World domination");
let id = project.add_resource(Resource::new("Stimpack".parse().unwrap()));

assert!(project.resource(id).is_some());
project.rm_resource(id).unwrap();
assert!(project.resource(id).is_none());
assert!(project.rm_resource(id).is_err());
Source

pub fn resource_mut(&mut self, id: Uuid) -> Option<&mut Resource>

Get a mutable reference to a resource in the project, by its stable Uuid.

§Example
use planter_core::{resources::Resource, project::Project};

let mut project = Project::new("World domination");
let id = project.add_resource(Resource::new("Crobwar".parse().unwrap()));

// Fixing a typo in a resource's title:
project.resource_mut(id).unwrap().set_title("Crowbar".parse().unwrap());
assert_eq!(project.resource(id).unwrap().title(), "Crowbar");
Source

pub fn resources(&self) -> impl Iterator<Item = &Resource>

Returns the list of resources in the project.

§Example
use planter_core::{resources::Resource, project::Project};

let mut project = Project::new("World domination");
project.add_resource(Resource::new("Crowbar".parse().unwrap()));
assert_eq!(project.resources().count(), 1);
Source

pub fn add_purchase( &mut self, resource_id: Uuid, purchase: Purchase, ) -> Result<Uuid>

Records a Purchase against a resource in the project’s pool, returning its Purchase::id. The project-level counterpart to Resource::add_purchase.

§Errors

Returns an error if resource_id doesn’t refer to a resource in Self::resources.

§Example
use planter_core::{resources::{Purchase, Resource}, project::Project, money::{Money, Currency}};

let mut project = Project::new("Build");
let stimpack = project.add_resource(Resource::new("Stimpack".parse().unwrap()));
project.add_purchase(
    stimpack,
    Purchase::builder().quantity(10).unit_price(Money::from_minor_units(400, Currency::EUR)).build(),
).unwrap();
assert_eq!(project.resource(stimpack).unwrap().purchases().count(), 1);
Source

pub fn rm_purchase( &mut self, resource_id: Uuid, purchase_id: Uuid, ) -> Result<Purchase>

Removes a resource’s purchase by id, returning it. The project-level counterpart to Resource::rm_purchase.

§Errors

Returns an error if resource_id doesn’t refer to a resource in Self::resources, or if that resource has no purchase with purchase_id.

Source

pub fn purchase_mut( &mut self, resource_id: Uuid, purchase_id: Uuid, ) -> Result<&mut Purchase>

Mutable access to one of a resource’s purchases, for editing it in place. The project-level counterpart to Resource::purchase_mut.

§Errors

Returns an error if resource_id doesn’t refer to a resource in Self::resources, or if that resource has no purchase with purchase_id.

§Example
use planter_core::{resources::{Purchase, Resource}, project::Project, money::{Money, Currency}};

let mut project = Project::new("Build");
let stimpack = project.add_resource(Resource::new("Stimpack".parse().unwrap()));
let purchase = project.add_purchase(
    stimpack,
    Purchase::builder().quantity(10).unit_price(Money::from_minor_units(400, Currency::EUR)).build(),
).unwrap();
project.purchase_mut(stimpack, purchase).unwrap().set_unit_price(Money::from_minor_units(420, Currency::EUR));
assert_eq!(
    project.resource(stimpack).unwrap().purchases().next().unwrap().unit_price(),
    Money::from_minor_units(420, Currency::EUR),
);
Source

pub fn assign_resource( &mut self, task_id: Uuid, resource_id: Uuid, ) -> Result<()>

Records that task_id engages one unit of resource_id, checking that both the task and the resource exist in the project. For more than one unit, use Self::assign_resource_units.

A task engages any given resource at most once: a second call for the same resource replaces the quantity.

§Errors

Returns an error if task_id doesn’t refer to a task in the project, or if resource_id doesn’t refer to a resource in Self::resources.

§Example
use planter_core::{project::Project, task::Task, resources::Resource};

let mut project = Project::new("World domination");
let task_id = project.add_task(Task::new("Find a crowbar"));
let resource_id = project.add_resource(Resource::new("Crowbar".parse().unwrap()));

project.assign_resource(task_id, resource_id).unwrap();
assert_eq!(project.task(task_id).unwrap().assignments().count(), 1);
Source

pub fn assign_resource_units( &mut self, task_id: Uuid, resource_id: Uuid, units: NonZeroU32, ) -> Result<()>

Records that task_id engages units of resource_id, checking that both the task and the resource exist in the project.

A task engages any given resource at most once: a second call for the same resource replaces the quantity. units is how many of the resource the task draws at once, e.g. 2 of a 4-person crew, or 3 units of a material. To remove an assignment, use Self::unassign_resource instead of trying to assign zero units.

§Errors

Returns an error if task_id doesn’t refer to a task in the project, or if resource_id doesn’t refer to a resource in Self::resources.

Source

pub fn unassign_resource( &mut self, task_id: Uuid, resource_id: Uuid, ) -> Result<u32>

Removes task_id’s assignment for resource_id, returning the quantity it engaged. The counterpart to Self::assign_resource.

§Errors

Returns an error if task_id doesn’t refer to a task in the project, or if the task didn’t engage resource_id.

§Example
use planter_core::{project::Project, task::Task, resources::Resource};
use std::num::NonZeroU32;

let mut project = Project::new("World domination");
let task_id = project.add_task(Task::new("Find a stimpack"));
let resource_id = project.add_resource(Resource::new("Stimpack".parse().unwrap()));
project.assign_resource_units(task_id, resource_id, NonZeroU32::new(5).unwrap()).unwrap();

assert_eq!(project.unassign_resource(task_id, resource_id).unwrap(), 5);
assert!(project.unassign_resource(task_id, resource_id).is_err());
assert_eq!(project.task(task_id).unwrap().assignments().count(), 0);
Source

pub fn total_cost(&self) -> MultiCurrencyAmount

Sums the project’s total cost: every resource’s one-time purchase_cost, plus, for every task, each assignment’s hourly cost over the task’s duration (see Self::task_cost).

Each amount is priced in its resource’s own currency; amounts in different currencies are kept as separate entries, never combined. Arithmetic saturates instead of overflowing.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
project.add_task(Task::new("Become world leader"));
assert!(project.total_cost().is_empty());
Source

pub fn task_cost(&self, task_id: Uuid) -> Result<MultiCurrencyAmount>

The cost of a single task: each assignment’s hourly_rate * hours * quantity, priced in the resource’s own currency and grouped into a MultiCurrencyAmount. A resource with no rate, or an assignment whose resource isn’t in the project, contributes nothing. One-time purchase costs aren’t counted here; those belong to the resource.

§Errors

Returns an error if task_id doesn’t refer to a task in the project.

§Example
use planter_core::{project::Project, task::Task};

let mut project = Project::new("World domination");
let task_id = project.add_task(Task::new("Become world leader"));
assert!(project.task_cost(task_id).unwrap().is_empty());
Source

pub fn resource_cost(&self, resource_id: Uuid) -> Result<MultiCurrencyAmount>

The total a single resource has cost the project: its one-time purchase_cost plus its hourly cost across every task that engages it.

Summing this over every resource gives the same figure as Self::total_cost.

§Errors

Returns an error if resource_id doesn’t refer to a resource in Self::resources.

§Example
use planter_core::{project::Project, task::Task, resources::{Purchase, Resource}, money::{Currency, Money}};
use chrono::Duration;

let mut project = Project::new("Build");
let digger_id = project.add_resource(
    Resource::new("Crowbar".parse().unwrap()).at_hourly_rate(Money::from_minor_units(30, Currency::EUR)),
);
project.add_purchase(
    digger_id,
    Purchase::builder().quantity(1).unit_price(Money::from_minor_units(1_000, Currency::EUR)).build(),
).unwrap();

let task_id = project.add_task(Task::new("Dig"));
project.edit_task_duration(task_id, Duration::hours(4).try_into().unwrap()).unwrap();
project.assign_resource(task_id, digger_id).unwrap();

// 1000 purchased + 30 * 4h used
assert_eq!(
    project.resource_cost(digger_id).unwrap().in_currency(Currency::EUR),
    Some(Money::from_minor_units(1_120, Currency::EUR)),
);
Source

pub fn add_stakeholder(&mut self, stakeholder: Stakeholder)

Adds a stakeholder to the project.

§Arguments
  • stakeholder - The stakeholder to add to the project.
§Example
use planter_core::{stakeholders::Stakeholder, project::Project, person::Person};

let mut project = Project::new("World domination");
let person = Person::new("Margherita", "Hack").unwrap();
project.add_stakeholder(Stakeholder::Individual {
  person,
  description: None,
});
assert_eq!(project.stakeholders().len(), 1);
Source

pub fn stakeholders(&self) -> &[Stakeholder]

Returns a reference to the list of stakeholders associated with the project.

§Example
use planter_core::{stakeholders::Stakeholder, project::Project, person::Person};

let mut project = Project::new("World domination");
let person = Person::new("Margherita", "Hack").unwrap();
project.add_stakeholder(Stakeholder::Individual {
  person,
  description: None,
});
assert_eq!(project.stakeholders().len(), 1);
Source

pub fn rm_stakeholder(&mut self, index: usize) -> Option<Stakeholder>

Removes a stakeholder from the project by index.

§Arguments
  • index - The index of the stakeholder to remove.
§Returns

The removed stakeholder, or None if the index is out of bounds.

§Example
use planter_core::{stakeholders::Stakeholder, project::Project, person::Person};

let mut project = Project::new("World domination");
let person = Person::new("Margherita", "Hack").unwrap();
project.add_stakeholder(Stakeholder::Individual { person, description: None });
assert_eq!(project.stakeholders().len(), 1);
let removed = project.rm_stakeholder(0);
assert!(removed.is_some());
assert_eq!(project.stakeholders().len(), 0);

Trait Implementations§

Source§

impl Debug for Project

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Project

Source§

fn default() -> Project

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.