Füge neue SQL-Abfragen für die Abfrage von Lagerbeständen nach Typ hinzu: Implementiere QUERY_GET_REGION_STOCKS_BY_TYPE und QUERY_GET_USER_STOCKS_BY_TYPE, um die Abfrage von Lagerbeständen zu optimieren. Aktualisiere die Logik in events.rs, um die neuen Abfragen zu verwenden und erweitere die Struktur StorageDamageInfo, um zusätzliche Informationen zu zerstörten Einheiten und betroffenen Regionen zu speichern. Ergänze die Dokumentation in AGENTS.md mit Projektleitlinien und Entwicklungsbefehlen.
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 1m48s
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 1m48s
This commit is contained in:
29
AGENTS.md
Normal file
29
AGENTS.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Project Structure & Module Organization
|
||||
- **Daemon-Worker Architecture**: A standalone Rust daemon for the Falukant game backend, managing game mechanics through background workers.
|
||||
- **Workers (`./src/worker/`)**: Modular task handlers (e.g., `PoliticsWorker`, `FalukantFamilyWorker`, `EventsWorker`) that execute periodic game logic ("ticks"). Most workers extend the `BaseWorker` logic.
|
||||
- **Database Layer**: Uses PostgreSQL for persistence. Core SQL queries are centralized in `./src/worker/sql.rs`, while connection management resides in `./src/db/`.
|
||||
- **Real-time Communication**: `./src/websocket_server.rs` manages client connections, broadcasting game state updates via `./src/message_broker.rs`.
|
||||
- **Migrations**: Database schema changes are managed manually via SQL scripts in `./migrations/`.
|
||||
- **Documentation**: Detailed technical specs and handoff notes are located in `./docs/`.
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
- `cargo build`: Compile the project.
|
||||
- `cargo clippy`: Run the linter to ensure code quality.
|
||||
- `cargo run`: Start the daemon.
|
||||
- `cargo fmt`: Format the codebase according to Rust standards.
|
||||
- `cargo check`: Rapidly check for compilation errors.
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
- **Rust Standards**: Follows idiomatic Rust conventions (snake_case for variables/functions, PascalCase for types).
|
||||
- **Linter**: Enforced via `clippy`. Use `cargo clippy` before committing.
|
||||
- **Database Logic**: Prefer centralizing complex SQL queries in `./src/worker/sql.rs` rather than inlining them in worker logic.
|
||||
|
||||
## Testing Guidelines
|
||||
- **Manual Verification**: No automated test suite exists (`cargo test` returns no results). Verify changes by running the daemon and inspecting database state or WebSocket output.
|
||||
- **Smoke Tests**: Follow instructions in `./docs/` for feature-specific manual testing (e.g., `./docs/FALUKANT_DEATH_SUCCESSION_SMOKE_TEST.md`).
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
- **Commit Messages**: Primarily written in German, though English is acceptable. Messages typically start with an imperative verb (e.g., "Füge", "Verbessere", "Behebe", "Refactor", "Enhance").
|
||||
- **Context**: Reference specific features or workers in the commit subject to maintain clarity in the history.
|
||||
@@ -20,6 +20,8 @@ use crate::worker::sql::{
|
||||
QUERY_INSERT_MONEY_HISTORY,
|
||||
QUERY_GET_REGION_STOCKS,
|
||||
QUERY_GET_USER_STOCKS,
|
||||
QUERY_GET_REGION_STOCKS_BY_TYPE,
|
||||
QUERY_GET_USER_STOCKS_BY_TYPE,
|
||||
QUERY_UPDATE_STOCK_CAPACITY,
|
||||
QUERY_UPDATE_STOCK_CAPACITY_REGIONAL,
|
||||
QUERY_GET_REGION_HOUSES,
|
||||
@@ -139,6 +141,8 @@ struct StorageDamageInfo {
|
||||
storage_destruction_percent: f64,
|
||||
affected_stocks: i32,
|
||||
destroyed_stocks: i32,
|
||||
destroyed_inventory_units: i64,
|
||||
affected_region_ids: Vec<i32>,
|
||||
}
|
||||
|
||||
/// Parameter für regionale Lager-Schäden
|
||||
@@ -224,18 +228,18 @@ impl EventsWorker {
|
||||
EventEffect::StorageDamage {
|
||||
probability: 1.0,
|
||||
stock_type_label: "field".to_string(),
|
||||
inventory_damage_min_percent: 5.0,
|
||||
inventory_damage_max_percent: 75.0,
|
||||
inventory_damage_min_percent: 35.0,
|
||||
inventory_damage_max_percent: 90.0,
|
||||
storage_destruction_min_percent: 0.0,
|
||||
storage_destruction_max_percent: 50.0,
|
||||
storage_destruction_max_percent: 0.0,
|
||||
},
|
||||
EventEffect::StorageDamage {
|
||||
probability: 1.0,
|
||||
stock_type_label: "wood".to_string(),
|
||||
inventory_damage_min_percent: 0.0,
|
||||
inventory_damage_max_percent: 25.0,
|
||||
storage_destruction_min_percent: 0.0,
|
||||
storage_destruction_max_percent: 10.0,
|
||||
inventory_damage_min_percent: 20.0,
|
||||
inventory_damage_max_percent: 55.0,
|
||||
storage_destruction_min_percent: 8.0,
|
||||
storage_destruction_max_percent: 25.0,
|
||||
},
|
||||
// Verbleibende Lager können durch den Sturm beschädigt werden und Kapazität verlieren
|
||||
EventEffect::StorageCapacityChange {
|
||||
@@ -271,23 +275,32 @@ impl EventsWorker {
|
||||
title: "Lagerbrand".to_string(),
|
||||
description: "Ein Feuer hat Teile deines Lagers beschädigt.".to_string(),
|
||||
effects: vec![
|
||||
// Feldlager: Lagerbestand kann zerstört werden, Lager können zerstört werden
|
||||
// Feldlager: haeufig Inhaltsverlust, aber Lager selbst bleibt erhalten
|
||||
EventEffect::StorageDamage {
|
||||
probability: 1.0,
|
||||
stock_type_label: "field".to_string(),
|
||||
inventory_damage_min_percent: 0.0,
|
||||
inventory_damage_max_percent: 100.0,
|
||||
inventory_damage_min_percent: 45.0,
|
||||
inventory_damage_max_percent: 95.0,
|
||||
storage_destruction_min_percent: 0.0,
|
||||
storage_destruction_max_percent: 50.0,
|
||||
storage_destruction_max_percent: 0.0,
|
||||
},
|
||||
// Holzlager: Lagerbestand kann zerstört werden, Lager können zerstört werden
|
||||
// Holzlager: Brand richtet hohen Schaden an Inhalt und Lager an
|
||||
EventEffect::StorageDamage {
|
||||
probability: 1.0,
|
||||
stock_type_label: "wood".to_string(),
|
||||
inventory_damage_min_percent: 0.0,
|
||||
inventory_damage_max_percent: 100.0,
|
||||
inventory_damage_min_percent: 35.0,
|
||||
inventory_damage_max_percent: 85.0,
|
||||
storage_destruction_min_percent: 12.0,
|
||||
storage_destruction_max_percent: 35.0,
|
||||
},
|
||||
// Steinlager: nur durch Brand betroffen, selten und nur geringer Inhaltsverlust
|
||||
EventEffect::StorageDamage {
|
||||
probability: 0.25,
|
||||
stock_type_label: "stone".to_string(),
|
||||
inventory_damage_min_percent: 3.0,
|
||||
inventory_damage_max_percent: 12.0,
|
||||
storage_destruction_min_percent: 0.0,
|
||||
storage_destruction_max_percent: 50.0,
|
||||
storage_destruction_max_percent: 0.0,
|
||||
},
|
||||
// Verbleibende Lager können durch das Feuer beschädigt werden und Kapazität verlieren
|
||||
EventEffect::StorageCapacityChange {
|
||||
@@ -297,6 +310,33 @@ impl EventsWorker {
|
||||
},
|
||||
],
|
||||
},
|
||||
RandomEvent {
|
||||
id: "warehouse_raid".to_string(),
|
||||
probability_per_minute: 0.003, // 0.3% pro Minute
|
||||
event_type: EventType::Personal,
|
||||
title: "Lagerraub".to_string(),
|
||||
description: "Raeuber haben Teile deiner Lager gepluendert.".to_string(),
|
||||
effects: vec![
|
||||
// Holzlager: bei Raub oft stark betroffen, inkl. Lagerschaden
|
||||
EventEffect::StorageDamage {
|
||||
probability: 1.0,
|
||||
stock_type_label: "wood".to_string(),
|
||||
inventory_damage_min_percent: 25.0,
|
||||
inventory_damage_max_percent: 70.0,
|
||||
storage_destruction_min_percent: 6.0,
|
||||
storage_destruction_max_percent: 20.0,
|
||||
},
|
||||
// Feldlager: haeufig Inhaltsverlust, aber kein Lagerschaden
|
||||
EventEffect::StorageDamage {
|
||||
probability: 1.0,
|
||||
stock_type_label: "field".to_string(),
|
||||
inventory_damage_min_percent: 30.0,
|
||||
inventory_damage_max_percent: 80.0,
|
||||
storage_destruction_min_percent: 0.0,
|
||||
storage_destruction_max_percent: 0.0,
|
||||
},
|
||||
],
|
||||
},
|
||||
RandomEvent {
|
||||
id: "character_illness".to_string(),
|
||||
probability_per_minute: 0.004, // 0.4% pro Minute (reduziert)
|
||||
@@ -1130,6 +1170,16 @@ impl EventsWorker {
|
||||
.and_then(|v| v.parse::<i32>().ok())
|
||||
.unwrap_or(0);
|
||||
|
||||
let stock_type_label = row
|
||||
.get("stock_type_label")
|
||||
.map(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
// Eisenlager sind unzerstoerbar (kein struktureller Event-Schaden)
|
||||
if stock_type_label == "iron" {
|
||||
continue;
|
||||
}
|
||||
|
||||
if current_capacity > 0 {
|
||||
conn.execute("update_stock_capacity", &[&percent_change, &stock_id])?;
|
||||
affected_stocks += 1;
|
||||
@@ -1185,6 +1235,16 @@ impl EventsWorker {
|
||||
.and_then(|v| v.parse::<i32>().ok())
|
||||
.unwrap_or(0);
|
||||
|
||||
let stock_type_label = row
|
||||
.get("stock_type_label")
|
||||
.map(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
// Eisenlager sind unzerstoerbar (kein struktureller Event-Schaden)
|
||||
if stock_type_label == "iron" {
|
||||
continue;
|
||||
}
|
||||
|
||||
if current_capacity > 0 {
|
||||
conn.execute("update_stock_capacity_regional", &[&percent_change, &stock_id])?;
|
||||
affected_stocks += 1;
|
||||
@@ -1532,6 +1592,8 @@ impl EventsWorker {
|
||||
"storage_destruction_percent": damage_info.storage_destruction_percent,
|
||||
"affected_stocks": damage_info.affected_stocks,
|
||||
"destroyed_stocks": damage_info.destroyed_stocks,
|
||||
"destroyed_inventory_units": damage_info.destroyed_inventory_units,
|
||||
"affected_region_ids": damage_info.affected_region_ids,
|
||||
})));
|
||||
}
|
||||
|
||||
@@ -1571,10 +1633,13 @@ impl EventsWorker {
|
||||
return Ok(Some(json!({
|
||||
"type": "storage_damage",
|
||||
"stock_type": stock_type_label,
|
||||
"region_id": region_id,
|
||||
"inventory_damage_percent": damage_info.inventory_damage_percent,
|
||||
"storage_destruction_percent": damage_info.storage_destruction_percent,
|
||||
"affected_stocks": damage_info.affected_stocks,
|
||||
"destroyed_stocks": damage_info.destroyed_stocks,
|
||||
"destroyed_inventory_units": damage_info.destroyed_inventory_units,
|
||||
"affected_region_ids": damage_info.affected_region_ids,
|
||||
})));
|
||||
}
|
||||
|
||||
@@ -2138,8 +2203,8 @@ impl EventsWorker {
|
||||
};
|
||||
|
||||
// 2. Hole alle Stocks dieses Typs in der Region mit ihren Branches
|
||||
conn.prepare("get_region_stocks", QUERY_GET_REGION_STOCKS)?;
|
||||
let stock_rows = conn.execute("get_region_stocks", &[¶ms.region_id, &stock_type_id])?;
|
||||
conn.prepare("get_region_stocks_by_type", QUERY_GET_REGION_STOCKS_BY_TYPE)?;
|
||||
let stock_rows = conn.execute("get_region_stocks_by_type", &[¶ms.region_id, &stock_type_id])?;
|
||||
|
||||
if stock_rows.is_empty() {
|
||||
eprintln!(
|
||||
@@ -2151,6 +2216,8 @@ impl EventsWorker {
|
||||
storage_destruction_percent: 0.0,
|
||||
affected_stocks: 0,
|
||||
destroyed_stocks: 0,
|
||||
destroyed_inventory_units: 0,
|
||||
affected_region_ids: vec![params.region_id],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2161,7 +2228,7 @@ impl EventsWorker {
|
||||
rng.gen_range(params.storage_destruction_min_percent..=params.storage_destruction_max_percent);
|
||||
|
||||
let total_stocks = stock_rows.len();
|
||||
let stocks_to_destroy = ((total_stocks as f64 * storage_destruction_percent / 100.0)
|
||||
let stocks_to_destroy_requested = ((total_stocks as f64 * storage_destruction_percent / 100.0)
|
||||
.round() as usize)
|
||||
.min(total_stocks);
|
||||
|
||||
@@ -2172,6 +2239,7 @@ impl EventsWorker {
|
||||
|
||||
let mut affected_stocks = 0;
|
||||
let mut processed_stocks = std::collections::HashSet::new();
|
||||
let mut destroyed_inventory_units: i64 = 0;
|
||||
|
||||
for row in &inventory_rows {
|
||||
let inventory_id: Option<i32> = row
|
||||
@@ -2200,6 +2268,7 @@ impl EventsWorker {
|
||||
if inventory_quantity > 0 {
|
||||
let damage = (inventory_quantity as f64 * inventory_damage_percent / 100.0).round() as i32;
|
||||
let new_quantity = (inventory_quantity - damage).max(0);
|
||||
destroyed_inventory_units += (inventory_quantity - new_quantity).max(0) as i64;
|
||||
|
||||
// Reduziere Lagerbestand pro Inventar-Eintrag
|
||||
conn.prepare("reduce_inventory", QUERY_REDUCE_INVENTORY)?;
|
||||
@@ -2214,18 +2283,39 @@ impl EventsWorker {
|
||||
|
||||
// 5. Zerstöre zufällig ausgewählte Stocks
|
||||
let mut destroyed_stocks = 0;
|
||||
if stocks_to_destroy > 0 {
|
||||
// Regelwerk:
|
||||
// - Nur Holzlager koennen als Lager zerstoert werden.
|
||||
// - Niemals mehr Lager zerstoeren als Lager mit betroffenem Inhalt.
|
||||
if stocks_to_destroy_requested > 0 && params.stock_type_label == "wood" {
|
||||
// Wähle zufällige Stocks zum Zerstören
|
||||
let mut stock_ids_to_destroy: Vec<i32> = stock_rows
|
||||
.iter()
|
||||
.filter_map(|row| row.get("stock_id").and_then(|v| v.parse::<i32>().ok()))
|
||||
.collect();
|
||||
|
||||
stock_ids_to_destroy.retain(|sid| processed_stocks.contains(sid));
|
||||
let stocks_to_destroy = stocks_to_destroy_requested
|
||||
.min(stock_ids_to_destroy.len())
|
||||
.min(affected_stocks as usize);
|
||||
|
||||
// Mische die Liste zufällig
|
||||
stock_ids_to_destroy.shuffle(rng);
|
||||
stock_ids_to_destroy.truncate(stocks_to_destroy);
|
||||
|
||||
for stock_id in &stock_ids_to_destroy {
|
||||
// Restbestand im zu zerstoerenden Lager zaehlen (zusaetzlicher Verlust)
|
||||
conn.prepare("get_stock_inventory", QUERY_GET_STOCK_INVENTORY)?;
|
||||
let doomed_items = conn.execute("get_stock_inventory", &[stock_id])?;
|
||||
for item_row in doomed_items {
|
||||
let qty = item_row
|
||||
.get("quantity")
|
||||
.and_then(|v| v.parse::<i32>().ok())
|
||||
.unwrap_or(0);
|
||||
if qty > 0 {
|
||||
destroyed_inventory_units += qty as i64;
|
||||
}
|
||||
}
|
||||
|
||||
// Lösche zuerst den Lagerbestand
|
||||
conn.prepare("delete_inventory", QUERY_DELETE_INVENTORY)?;
|
||||
conn.execute("delete_inventory", &[stock_id])?;
|
||||
@@ -2240,7 +2330,7 @@ impl EventsWorker {
|
||||
|
||||
// 6. Sicherstelle, dass Lagerbestand <= Lageranzahl für alle verbleibenden Stocks
|
||||
// Hole alle verbleibenden Stocks mit ihrem Lagerbestand
|
||||
let remaining_stock_rows = conn.execute("get_region_stocks", &[¶ms.region_id, &stock_type_id])?;
|
||||
let remaining_stock_rows = conn.execute("get_region_stocks_by_type", &[¶ms.region_id, &stock_type_id])?;
|
||||
|
||||
for row in remaining_stock_rows {
|
||||
let stock_id: Option<i32> = row
|
||||
@@ -2299,6 +2389,8 @@ impl EventsWorker {
|
||||
storage_destruction_percent,
|
||||
affected_stocks,
|
||||
destroyed_stocks,
|
||||
destroyed_inventory_units,
|
||||
affected_region_ids: vec![params.region_id],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2331,8 +2423,8 @@ impl EventsWorker {
|
||||
};
|
||||
|
||||
// 2. Hole alle Stocks dieses Typs für alle Branches des Spielers
|
||||
conn.prepare("get_user_stocks", QUERY_GET_USER_STOCKS)?;
|
||||
let stock_rows = conn.execute("get_user_stocks", &[¶ms.user_id, &stock_type_id])?;
|
||||
conn.prepare("get_user_stocks_by_type", QUERY_GET_USER_STOCKS_BY_TYPE)?;
|
||||
let stock_rows = conn.execute("get_user_stocks_by_type", &[¶ms.user_id, &stock_type_id])?;
|
||||
|
||||
if stock_rows.is_empty() {
|
||||
eprintln!(
|
||||
@@ -2344,6 +2436,8 @@ impl EventsWorker {
|
||||
storage_destruction_percent: 0.0,
|
||||
affected_stocks: 0,
|
||||
destroyed_stocks: 0,
|
||||
destroyed_inventory_units: 0,
|
||||
affected_region_ids: Vec::new(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2354,7 +2448,7 @@ impl EventsWorker {
|
||||
rng.gen_range(params.storage_destruction_min_percent..=params.storage_destruction_max_percent);
|
||||
|
||||
let total_stocks = stock_rows.len();
|
||||
let stocks_to_destroy = ((total_stocks as f64 * storage_destruction_percent / 100.0)
|
||||
let stocks_to_destroy_requested = ((total_stocks as f64 * storage_destruction_percent / 100.0)
|
||||
.round() as usize)
|
||||
.min(total_stocks);
|
||||
|
||||
@@ -2365,6 +2459,7 @@ impl EventsWorker {
|
||||
|
||||
let mut affected_stocks = 0;
|
||||
let mut processed_stocks = std::collections::HashSet::new();
|
||||
let mut destroyed_inventory_units: i64 = 0;
|
||||
|
||||
for row in &inventory_rows {
|
||||
let inventory_id: Option<i32> = row
|
||||
@@ -2393,6 +2488,7 @@ impl EventsWorker {
|
||||
if inventory_quantity > 0 {
|
||||
let damage = (inventory_quantity as f64 * inventory_damage_percent / 100.0).round() as i32;
|
||||
let new_quantity = (inventory_quantity - damage).max(0);
|
||||
destroyed_inventory_units += (inventory_quantity - new_quantity).max(0) as i64;
|
||||
|
||||
// Reduziere Lagerbestand pro Inventar-Eintrag
|
||||
conn.prepare("reduce_inventory_personal", QUERY_REDUCE_INVENTORY_PERSONAL)?;
|
||||
@@ -2405,20 +2501,38 @@ impl EventsWorker {
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Zerstöre zufällig ausgewählte Stocks (nur für field und wood)
|
||||
// 5. Zerstöre zufällig ausgewählte Stocks (nur Holzlager)
|
||||
let mut destroyed_stocks = 0;
|
||||
if stocks_to_destroy > 0 && (params.stock_type_label == "field" || params.stock_type_label == "wood") {
|
||||
if stocks_to_destroy_requested > 0 && params.stock_type_label == "wood" {
|
||||
// Wähle zufällige Stocks zum Zerstören
|
||||
let mut stock_ids_to_destroy: Vec<i32> = stock_rows
|
||||
.iter()
|
||||
.filter_map(|row| row.get("stock_id").and_then(|v| v.parse::<i32>().ok()))
|
||||
.collect();
|
||||
|
||||
stock_ids_to_destroy.retain(|sid| processed_stocks.contains(sid));
|
||||
let stocks_to_destroy = stocks_to_destroy_requested
|
||||
.min(stock_ids_to_destroy.len())
|
||||
.min(affected_stocks as usize);
|
||||
|
||||
// Mische die Liste zufällig
|
||||
stock_ids_to_destroy.shuffle(rng);
|
||||
stock_ids_to_destroy.truncate(stocks_to_destroy);
|
||||
|
||||
for stock_id in &stock_ids_to_destroy {
|
||||
// Restbestand im zu zerstoerenden Lager zaehlen (zusaetzlicher Verlust)
|
||||
conn.prepare("get_stock_inventory_personal", QUERY_GET_STOCK_INVENTORY_PERSONAL)?;
|
||||
let doomed_items = conn.execute("get_stock_inventory_personal", &[stock_id])?;
|
||||
for item_row in doomed_items {
|
||||
let qty = item_row
|
||||
.get("quantity")
|
||||
.and_then(|v| v.parse::<i32>().ok())
|
||||
.unwrap_or(0);
|
||||
if qty > 0 {
|
||||
destroyed_inventory_units += qty as i64;
|
||||
}
|
||||
}
|
||||
|
||||
// Lösche zuerst den Lagerbestand
|
||||
conn.prepare("delete_inventory_personal", QUERY_DELETE_INVENTORY_PERSONAL)?;
|
||||
conn.execute("delete_inventory_personal", &[stock_id])?;
|
||||
@@ -2432,7 +2546,7 @@ impl EventsWorker {
|
||||
}
|
||||
|
||||
// 6. Sicherstelle, dass Lagerbestand <= Lageranzahl für alle verbleibenden Stocks
|
||||
let remaining_stock_rows = conn.execute("get_user_stocks", &[¶ms.user_id, &stock_type_id])?;
|
||||
let remaining_stock_rows = conn.execute("get_user_stocks_by_type", &[¶ms.user_id, &stock_type_id])?;
|
||||
|
||||
for row in remaining_stock_rows {
|
||||
let stock_id: Option<i32> = row
|
||||
@@ -2486,11 +2600,23 @@ impl EventsWorker {
|
||||
}
|
||||
}
|
||||
|
||||
let mut affected_region_ids = std::collections::BTreeSet::new();
|
||||
for row in &stock_rows {
|
||||
if let Some(rid) = row
|
||||
.get("region_id")
|
||||
.and_then(|v| v.parse::<i32>().ok())
|
||||
{
|
||||
affected_region_ids.insert(rid);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(StorageDamageInfo {
|
||||
inventory_damage_percent,
|
||||
storage_destruction_percent,
|
||||
affected_stocks,
|
||||
destroyed_stocks,
|
||||
destroyed_inventory_units,
|
||||
affected_region_ids: affected_region_ids.into_iter().collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,9 +753,12 @@ UPDATE falukant_data.inventory SET quantity = $1 WHERE id = $2;
|
||||
"#;
|
||||
|
||||
pub const QUERY_GET_USER_STOCKS: &str = r#"
|
||||
SELECT s.id AS stock_id, s.quantity AS current_capacity
|
||||
SELECT s.id AS stock_id,
|
||||
s.quantity AS current_capacity,
|
||||
st.label_tr AS stock_type_label
|
||||
FROM falukant_data.stock s
|
||||
JOIN falukant_data.branch b ON s.branch_id = b.id
|
||||
LEFT JOIN falukant_type.stock st ON st.id = s.stock_type_id
|
||||
WHERE b.falukant_user_id = $1;
|
||||
"#;
|
||||
|
||||
@@ -766,9 +769,12 @@ UPDATE falukant_data.stock
|
||||
"#;
|
||||
|
||||
pub const QUERY_GET_REGION_STOCKS: &str = r#"
|
||||
SELECT s.id AS stock_id, s.quantity AS current_capacity
|
||||
SELECT s.id AS stock_id,
|
||||
s.quantity AS current_capacity,
|
||||
st.label_tr AS stock_type_label
|
||||
FROM falukant_data.stock s
|
||||
JOIN falukant_data.branch b ON s.branch_id = b.id
|
||||
LEFT JOIN falukant_type.stock st ON st.id = s.stock_type_id
|
||||
WHERE b.region_id = $1;
|
||||
"#;
|
||||
|
||||
@@ -2699,6 +2705,18 @@ pub const QUERY_GET_INVENTORY_ITEMS: &str = r#"
|
||||
SELECT i.id AS inventory_id, i.quantity AS inventory_quantity, i.stock_id FROM falukant_data.inventory i JOIN falukant_data.stock s ON i.stock_id = s.id JOIN falukant_data.branch b ON s.branch_id = b.id WHERE b.region_id = $1 AND s.stock_type_id = $2;
|
||||
"#;
|
||||
|
||||
pub const QUERY_GET_REGION_STOCKS_BY_TYPE: &str = r#"
|
||||
SELECT s.id AS stock_id,
|
||||
s.quantity AS stock_capacity,
|
||||
COALESCE(SUM(i.quantity), 0)::int AS inventory_quantity
|
||||
FROM falukant_data.stock s
|
||||
JOIN falukant_data.branch b ON s.branch_id = b.id
|
||||
LEFT JOIN falukant_data.inventory i ON i.stock_id = s.id
|
||||
WHERE b.region_id = $1
|
||||
AND s.stock_type_id = $2
|
||||
GROUP BY s.id, s.quantity;
|
||||
"#;
|
||||
|
||||
pub const QUERY_REDUCE_INVENTORY: &str = r#"
|
||||
UPDATE falukant_data.inventory SET quantity = $1 WHERE id = $2;
|
||||
"#;
|
||||
@@ -2726,6 +2744,19 @@ JOIN falukant_data.stock s ON i.stock_id = s.id
|
||||
JOIN falukant_data.branch b ON s.branch_id = b.id
|
||||
WHERE b.falukant_user_id = $1 AND s.stock_type_id = $2;
|
||||
"#;
|
||||
|
||||
pub const QUERY_GET_USER_STOCKS_BY_TYPE: &str = r#"
|
||||
SELECT s.id AS stock_id,
|
||||
b.region_id AS region_id,
|
||||
s.quantity AS stock_capacity,
|
||||
COALESCE(SUM(i.quantity), 0)::int AS inventory_quantity
|
||||
FROM falukant_data.stock s
|
||||
JOIN falukant_data.branch b ON s.branch_id = b.id
|
||||
LEFT JOIN falukant_data.inventory i ON i.stock_id = s.id
|
||||
WHERE b.falukant_user_id = $1
|
||||
AND s.stock_type_id = $2
|
||||
GROUP BY s.id, b.region_id, s.quantity;
|
||||
"#;
|
||||
// Produce worker queries
|
||||
pub const QUERY_GET_FINISHED_PRODUCTIONS: &str = r#"
|
||||
SELECT DISTINCT ON (p.id)
|
||||
|
||||
Reference in New Issue
Block a user