Spaces:
Sleeping
Sleeping
| use serde::{Deserialize, Serialize}; | |
| use solverforge::prelude::*; | |
| /// Customer job that must be inserted into exactly one technician route. | |
| /// | |
| /// This is problem data, not a planning entity. The solver does not mutate the | |
| /// visit itself; it mutates `TechnicianRoute.visits`, which stores indexes into | |
| /// the `FieldServicePlan.service_visits` vector. | |
| pub struct ServiceVisit { | |
| pub id: String, | |
| pub name: String, | |
| pub customer: String, | |
| pub location_idx: usize, | |
| pub duration_minutes: i32, | |
| pub earliest_minute: i32, | |
| pub latest_minute: i32, | |
| pub required_skill_mask: i64, | |
| pub required_parts_mask: i64, | |
| pub priority: i32, | |
| pub territory: String, | |
| } | |
| /// Constructor payload for `ServiceVisit`. | |
| /// | |
| /// Keeping construction grouped avoids a long positional argument list where a | |
| /// beginner could easily swap time windows, masks, or location indexes. | |
| pub struct ServiceVisitInit { | |
| pub id: String, | |
| pub name: String, | |
| pub customer: String, | |
| pub location_idx: usize, | |
| pub duration_minutes: i32, | |
| pub earliest_minute: i32, | |
| pub latest_minute: i32, | |
| pub required_skill_mask: i64, | |
| pub required_parts_mask: i64, | |
| pub priority: i32, | |
| pub territory: String, | |
| } | |
| impl ServiceVisit { | |
| /// Builds one immutable service-visit fact. | |
| pub fn new(init: ServiceVisitInit) -> Self { | |
| Self { | |
| id: init.id, | |
| name: init.name, | |
| customer: init.customer, | |
| location_idx: init.location_idx, | |
| duration_minutes: init.duration_minutes, | |
| earliest_minute: init.earliest_minute, | |
| latest_minute: init.latest_minute, | |
| required_skill_mask: init.required_skill_mask, | |
| required_parts_mask: init.required_parts_mask, | |
| priority: init.priority, | |
| territory: init.territory, | |
| } | |
| } | |
| } | |
| mod tests { | |
| use super::*; | |
| fn test_service_visit_construction() { | |
| let fact = ServiceVisit::new(ServiceVisitInit { | |
| id: "test-id".to_string(), | |
| name: "test".to_string(), | |
| customer: "test".to_string(), | |
| location_idx: Default::default(), | |
| duration_minutes: Default::default(), | |
| earliest_minute: Default::default(), | |
| latest_minute: Default::default(), | |
| required_skill_mask: Default::default(), | |
| required_parts_mask: Default::default(), | |
| priority: Default::default(), | |
| territory: "test".to_string(), | |
| }); | |
| assert_eq!(fact.id, "test-id"); | |
| assert_eq!(fact.name, "test"); | |
| let _ = &fact.customer; | |
| let _ = &fact.location_idx; | |
| let _ = &fact.duration_minutes; | |
| let _ = &fact.earliest_minute; | |
| let _ = &fact.latest_minute; | |
| let _ = &fact.required_skill_mask; | |
| let _ = &fact.required_parts_mask; | |
| let _ = &fact.priority; | |
| let _ = &fact.territory; | |
| } | |
| } | |