plansolve 0.27.0

Official Rust client library for the PlanSolve optimization API.
Documentation
use serde::{Deserialize, Serialize};

/// Lifecycle state of a solver run as recorded in the Jobs table.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(from = "i32", into = "i32")]
pub enum JobStatus {
    /// The job has not yet reached a terminal state.
    Pending,
    /// The job completed successfully.
    Succeeded,
    /// The job failed.
    Failed,
    /// The job's outcome could not be determined.
    Lost,
    /// Any status value not otherwise recognized.
    Unknown(i32),
}

impl From<i32> for JobStatus {
    fn from(value: i32) -> Self {
        match value {
            0 => JobStatus::Pending,
            1 => JobStatus::Succeeded,
            2 => JobStatus::Failed,
            3 => JobStatus::Lost,
            other => JobStatus::Unknown(other),
        }
    }
}

impl From<JobStatus> for i32 {
    fn from(status: JobStatus) -> Self {
        match status {
            JobStatus::Pending => 0,
            JobStatus::Succeeded => 1,
            JobStatus::Failed => 2,
            JobStatus::Lost => 3,
            JobStatus::Unknown(other) => other,
        }
    }
}

/// Payload for creating a new solver job via the public Jobs API.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateJobRequest {
    /// Subscription the job should be billed against. Resolved server-side from the
    /// authenticated tenant when omitted by the caller.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub subscription_id: Option<i32>,
    /// Identifier of the solver/model to run (e.g. `field_service`,
    /// `professional_services`, `shift`).
    pub solver_id: String,
    /// The optimization problem definition, as a raw JSON string matching the chosen
    /// solver's request schema.
    pub request: String,
}

/// A solver job as exposed by the public Jobs API.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JobDto {
    /// Internal numeric primary key. Not used to address the job over the API - use `job_id`.
    #[serde(default)]
    pub id: i64,
    /// Public, opaque job identifier used in API routes.
    #[serde(default)]
    pub job_id: Option<String>,
    /// Identifier of the tenant that owns the job.
    #[serde(default)]
    pub tenant_id: Option<String>,
    /// Subscription the job was charged against.
    #[serde(default)]
    pub subscription_id: i32,
    /// Solver family that produced the job (0 = Field Service, 1 = Professional Services, 2 = Shift).
    #[serde(default)]
    pub solver_type: i32,
    /// Lifecycle state of the job.
    pub status: JobStatus,
    /// UTC timestamp the job was created, as an ISO-8601 string.
    #[serde(default)]
    pub created_at: String,
    /// UTC timestamp the job reached a terminal state, or `None` while still in flight.
    #[serde(default)]
    pub completed_at: Option<String>,
    /// The optimization problem definition that was submitted, as raw JSON.
    #[serde(default)]
    pub request: Option<String>,
    /// The solver's result as raw JSON, or `None` until the job completes successfully.
    #[serde(default)]
    pub response: Option<String>,
    /// Whether a solver response is available for the job.
    #[serde(default)]
    pub has_response: bool,
    /// Number of schedulable items (visits/tasks/shifts) billed for this job.
    #[serde(default)]
    pub billed_items: i32,
    /// Identifier of the user who submitted the job, or `None` for API-key/system runs.
    #[serde(default)]
    pub user_id: Option<i32>,
    /// Display name of the user who submitted the job.
    #[serde(default)]
    pub user_name: Option<String>,
}

/// A single page of jobs plus the pagination metadata needed to navigate the set.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PagedResultOfJobDto {
    /// The jobs on the current page.
    #[serde(default)]
    pub items: Vec<JobDto>,
    /// Total number of items across all pages.
    #[serde(default)]
    pub total_count: i32,
    /// 1-based index of the current page.
    #[serde(default)]
    pub page: i32,
    /// Maximum number of items per page.
    #[serde(default)]
    pub page_size: i32,
    /// Total number of pages.
    #[serde(default)]
    pub total_pages: i32,
    /// Whether a page after the current one exists.
    #[serde(default)]
    pub has_next_page: bool,
    /// Whether a page before the current one exists.
    #[serde(default)]
    pub has_previous_page: bool,
}