PhoenixKitProjects.Schemas.Assignment (PhoenixKitProjects v0.8.0)

Copy Markdown View Source

A task instance within a project. Copies description and duration from the task template at creation time — editable independently.

Tracks who completed the task via completed_by_uuid + completed_at.

Summary

Types

t()

JSONB map of secondary-language overrides. Same shape as Project.translations_map/Task.translations_map.

Functions

Form-facing changeset. Does NOT allow setting completed_by_uuid or completed_at — those are server-owned fields (use status_changeset/2).

The display label for this assignment, locale-aware: the child project's name for a sub-project, otherwise the task template's title. Requires the relevant association (:child_project or :task) to be preloaded — both are in Projects' @assignment_preloads. lang may be nil (primary value).

Returns the assignment's description in the requested language, with primary-fallback semantics: empty/missing override → the primary description column, which itself may be nil (in which case the caller's typical pattern is to fall further back to the parent task's localized_description/2). The double-fallback chain keeps existing call sites like a.description || a.task.description working locale-aware: Assignment.localized_description(a, lang) || Task.localized_description(a.task, lang).

Server-trusted changeset that also allows setting completion fields. Use from context functions that own the completion transition, e.g. progress updates, explicit complete_assignment/2, or reopen_assignment/1.

True when this assignment embeds a child project (a sub-project row).

Changeset for the parent-side linking assignment of a sub-project.

DB-column field names that participate in the translations JSONB.

Types

t()

@type t() :: %PhoenixKitProjects.Schemas.Assignment{
  __meta__: term(),
  assigned_department:
    PhoenixKitStaff.Schemas.Department.t()
    | Ecto.Association.NotLoaded.t()
    | nil,
  assigned_department_uuid: UUIDv7.t() | nil,
  assigned_person:
    PhoenixKitStaff.Schemas.Person.t() | Ecto.Association.NotLoaded.t() | nil,
  assigned_person_uuid: UUIDv7.t() | nil,
  assigned_team:
    PhoenixKitStaff.Schemas.Team.t() | Ecto.Association.NotLoaded.t() | nil,
  assigned_team_uuid: UUIDv7.t() | nil,
  child_project:
    PhoenixKitProjects.Schemas.Project.t()
    | Ecto.Association.NotLoaded.t()
    | nil,
  child_project_uuid: UUIDv7.t() | nil,
  completed_at: DateTime.t() | nil,
  completed_by:
    PhoenixKit.Users.Auth.User.t() | Ecto.Association.NotLoaded.t() | nil,
  completed_by_uuid: UUIDv7.t() | nil,
  counts_weekends: boolean() | nil,
  dependencies:
    [PhoenixKitProjects.Schemas.Dependency.t()] | Ecto.Association.NotLoaded.t(),
  dependents: term(),
  description: String.t() | nil,
  estimated_duration: integer() | nil,
  estimated_duration_unit: String.t() | nil,
  inserted_at: DateTime.t() | nil,
  position: integer() | nil,
  progress_pct: integer() | nil,
  project:
    PhoenixKitProjects.Schemas.Project.t()
    | Ecto.Association.NotLoaded.t()
    | nil,
  project_uuid: UUIDv7.t() | nil,
  status: String.t() | nil,
  task:
    PhoenixKitProjects.Schemas.Task.t() | Ecto.Association.NotLoaded.t() | nil,
  task_uuid: UUIDv7.t() | nil,
  track_progress: boolean() | nil,
  translations: translations_map(),
  updated_at: DateTime.t() | nil,
  uuid: UUIDv7.t() | nil
}

translations_map()

@type translations_map() :: %{
  optional(String.t()) => %{optional(String.t()) => String.t()}
}

JSONB map of secondary-language overrides. Same shape as Project.translations_map/Task.translations_map.

Functions

changeset(assignment, attrs)

Form-facing changeset. Does NOT allow setting completed_by_uuid or completed_at — those are server-owned fields (use status_changeset/2).

label(assignment, lang \\ nil)

@spec label(t(), String.t() | nil) :: String.t() | nil

The display label for this assignment, locale-aware: the child project's name for a sub-project, otherwise the task template's title. Requires the relevant association (:child_project or :task) to be preloaded — both are in Projects' @assignment_preloads. lang may be nil (primary value).

Single source of truth so every render site (timeline title, comment header, dependency badge, remove-confirm, activity metadata) handles the sub-project case identically instead of dereferencing a nil task.

localized_description(a, lang)

@spec localized_description(t(), String.t() | nil) :: String.t() | nil

Returns the assignment's description in the requested language, with primary-fallback semantics: empty/missing override → the primary description column, which itself may be nil (in which case the caller's typical pattern is to fall further back to the parent task's localized_description/2). The double-fallback chain keeps existing call sites like a.description || a.task.description working locale-aware: Assignment.localized_description(a, lang) || Task.localized_description(a.task, lang).

status_changeset(assignment, attrs)

Server-trusted changeset that also allows setting completion fields. Use from context functions that own the completion transition, e.g. progress updates, explicit complete_assignment/2, or reopen_assignment/1.

statuses()

subproject?(assignment)

@spec subproject?(t()) :: boolean()

True when this assignment embeds a child project (a sub-project row).

subproject_changeset(assignment, attrs)

@spec subproject_changeset(t(), map()) :: Ecto.Changeset.t()

Changeset for the parent-side linking assignment of a sub-project.

Used both to create the linking row (create_subproject/2) and to sync the denormalized rollup fields whenever the child project changes (sync_project_rollup/1). Unlike changeset/2 it:

  • casts child_project_uuid and the server-owned rollup fields (status / progress_pct / estimated_duration / completed_at / completed_by_uuid) but never task_uuid — so a sub-project row can't be flipped into a task-backed one via this path;
  • does NOT require estimated_duration > 0 — a child with no tasks rolls up to 0 planned hours, which is legitimate.

translatable_fields()

@spec translatable_fields() :: [String.t()]

DB-column field names that participate in the translations JSONB.