diff --git a/src/worker/director.rs b/src/worker/director.rs index 9ce2e06..9c1ae93 100644 --- a/src/worker/director.rs +++ b/src/worker/director.rs @@ -35,15 +35,20 @@ use crate::worker::sql::{ QUERY_GET_USER_OFFICES, QUERY_CUMULATIVE_TAX_NO_EXEMPT, QUERY_CUMULATIVE_TAX_WITH_EXEMPT, + QUERY_GET_VEHICLES_TO_REPAIR_IN_REGION, + QUERY_REPAIR_VEHICLE, }; +use crate::worker::publish_update_status; #[derive(Debug, Clone)] struct Director { id: i32, branch_id: i32, + falukant_user_id: i32, may_produce: bool, may_sell: bool, may_start_transport: bool, + may_repair_vehicles: bool, } #[derive(Debug, Clone)] @@ -157,6 +162,14 @@ impl DirectorWorker { } for director in directors { + if director.may_repair_vehicles { + if let Err(err) = self.repair_vehicles(&director) { + eprintln!( + "[DirectorWorker] Fehler bei repair_vehicles für Director {}: {err}", + director.id + ); + } + } if director.may_produce { eprintln!( "[DirectorWorker] Starte Produktionsprüfung für Director {} (branch_id={})", @@ -192,15 +205,106 @@ impl DirectorWorker { Some(Director { id: row.get("id")?.parse().ok()?, branch_id: row.get("branch_id")?.parse().ok()?, + falukant_user_id: row.get("falukant_user_id")?.parse().ok()?, may_produce: row.get("may_produce").map(|v| v == "t" || v == "true").unwrap_or(false), may_sell: row.get("may_sell").map(|v| v == "t" || v == "true").unwrap_or(false), may_start_transport: row .get("may_start_transport") .map(|v| v == "t" || v == "true") .unwrap_or(false), + may_repair_vehicles: row + .get("may_repair_vehicles") + .map(|v| v == "t" || v == "true") + .unwrap_or(false), }) } + fn repair_vehicles(&mut self, director: &Director) -> Result<(), DbError> { + self.base + .set_current_step("DirectorWorker: repair_vehicles"); + + let mut conn = self + .base + .pool + .get() + .map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?; + + // Region des Directors/Branches bestimmen + conn.prepare("get_branch_region_for_repair", QUERY_GET_BRANCH_REGION)?; + let rows = conn.execute("get_branch_region_for_repair", &[&director.branch_id])?; + let region_id: i32 = rows + .first() + .and_then(|r| r.get("region_id")) + .and_then(|v| v.parse::().ok()) + .unwrap_or(-1); + if region_id < 0 { + return Ok(()); + } + + conn.prepare( + "get_vehicles_to_repair", + QUERY_GET_VEHICLES_TO_REPAIR_IN_REGION, + )?; + conn.prepare("repair_vehicle", QUERY_REPAIR_VEHICLE)?; + + let candidates = + conn.execute("get_vehicles_to_repair", &[&director.falukant_user_id, ®ion_id])?; + if candidates.is_empty() { + return Ok(()); + } + + let mut repaired = 0usize; + for row in candidates { + let vehicle_id = row + .get("vehicle_id") + .and_then(|v| v.parse::().ok()) + .unwrap_or(-1); + let condition = row + .get("condition") + .and_then(|v| v.parse::().ok()) + .unwrap_or(100.0); + let type_cost = row + .get("cost") + .and_then(|v| v.parse::().ok()) + .unwrap_or(0.0); + + if vehicle_id < 0 || type_cost <= 0.0 { + continue; + } + + // repairCost = round(type.cost * 0.8 * (100 - condition) / 100) + let repair_cost = (type_cost * 0.8 * (100.0 - condition) / 100.0).round(); + if repair_cost <= 0.0 { + continue; + } + + // Preconditions (wie Backend): + // - sufficientFunds: wir versuchen abzubuchen und überspringen bei Fehler + if let Err(_err) = self.base.change_falukant_user_money( + director.falukant_user_id, + -repair_cost, + &format!("repair vehicle {}", vehicle_id), + ) { + continue; + } + + // Fahrzeug auf 100 setzen + available_from in Zukunft (build_time_minutes) + let _ = conn.execute("repair_vehicle", &[&vehicle_id])?; + repaired += 1; + } + + if repaired > 0 { + eprintln!( + "[DirectorWorker] {} Fahrzeug(e) automatisch zur Reparatur gestartet (director_id={}, region_id={})", + repaired, director.id, region_id + ); + // Frontend: Branches/Status neu laden + publish_update_status(&self.base.broker, director.falukant_user_id); + } + + Ok(()) + } + fn start_productions(&mut self, director: &Director) -> Result<(), DbError> { self.base .set_current_step("DirectorWorker: start_productions"); diff --git a/src/worker/sql.rs b/src/worker/sql.rs index 23b17f5..9bd5d80 100644 --- a/src/worker/sql.rs +++ b/src/worker/sql.rs @@ -72,7 +72,14 @@ SELECT sell_cost, sell_cost AS original_sell_cost FROM falukant_type.product WHE "#; pub const QUERY_GET_DIRECTORS: &str = r#" -SELECT d.may_produce, d.may_sell, d.may_start_transport, b.id AS branch_id, fu.id AS falukantUserId, d.id +SELECT + d.may_produce, + d.may_sell, + d.may_start_transport, + d.may_repair_vehicles, + b.id AS branch_id, + fu.id AS falukant_user_id, + d.id FROM falukant_data.director d JOIN falukant_data.falukant_user fu ON fu.id = d.employer_user_id JOIN falukant_data.character c ON c.id = d.director_character_id @@ -80,6 +87,40 @@ JOIN falukant_data.branch b ON b.region_id = c.region_id AND b.falukant_user_id WHERE current_time BETWEEN '08:00:00' AND '17:00:00'; "#; +// Director: vehicle repair automation +pub const QUERY_GET_VEHICLES_TO_REPAIR_IN_REGION: &str = r#" +SELECT + v.id AS vehicle_id, + v.condition, + vt.cost, + COALESCE(vt.build_time_minutes, 0) AS build_time_minutes +FROM falukant_data.vehicle v +JOIN falukant_type.vehicle vt ON vt.id = v.vehicle_type_id +WHERE v.falukant_user_id = $1 + AND v.region_id = $2 + AND v.condition < 10 + AND v.condition < 100 + AND v.available_from <= NOW() + AND NOT EXISTS ( + SELECT 1 FROM falukant_data.transport t WHERE t.vehicle_id = v.id + ) +ORDER BY v.condition ASC, v.id ASC; +"#; + +pub const QUERY_REPAIR_VEHICLE: &str = r#" +UPDATE falukant_data.vehicle v + SET condition = 100, + available_from = NOW() + (COALESCE(vt.build_time_minutes, 0) * INTERVAL '1 minute'), + updated_at = NOW() + FROM falukant_type.vehicle vt + WHERE vt.id = v.vehicle_type_id + AND v.id = $1 + AND v.condition < 100 + AND v.available_from <= NOW() + AND NOT EXISTS (SELECT 1 FROM falukant_data.transport t WHERE t.vehicle_id = v.id) + RETURNING v.id AS vehicle_id, v.available_from, COALESCE(vt.build_time_minutes, 0) AS build_time_minutes; +"#; + pub const QUERY_GET_BEST_PRODUCTION: &str = r#" SELECT fdu.id falukant_user_id, CAST(fdu.money AS text) AS money, fdu.certificate, ftp.id product_id, ftp.label_tr, fdb.region_id, (SELECT SUM(quantity) FROM falukant_data.stock fds WHERE fds.branch_id = fdb.id) AS stock_size,