From f0747271300fb3e67f9d970d8421b8693bbcc08a Mon Sep 17 00:00:00 2001 From: JMARyA Date: Fri, 27 Sep 2024 09:19:32 +0200 Subject: [PATCH] stat --- Cargo.toml | 2 +- src/routes/item/mod.rs | 12 ++++++-- src/routes/item/stat.rs | 2 +- src/routes/item/supply.rs | 7 +++-- src/transaction.rs | 41 +++++++++++++++++++-------- src/variant.rs | 59 +++++++++++++++++++++++++++++++++++++-- 6 files changed, 101 insertions(+), 22 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 279e9a8..99c3aeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,4 @@ uuid = { version = "1.8.0", features = ["v4"] } mongod = { git = "https://git.hydrar.de/jmarya/mongod" } env_logger = "0.11.5" walkdir = "2.5.0" -reqwest = { version = "0.11", features = ["json"] } \ No newline at end of file +reqwest = { version = "0.11", features = ["json"] } diff --git a/src/routes/item/mod.rs b/src/routes/item/mod.rs index e93ec5e..6c10427 100644 --- a/src/routes/item/mod.rs +++ b/src/routes/item/mod.rs @@ -133,15 +133,21 @@ pub async fn unique_field_route( } #[get("/items/expired?")] -pub async fn expired_items_route(days: Option<&str>, t: Token, c: &State) -> FallibleApiResponse { +pub async fn expired_items_route( + days: Option<&str>, + t: Token, + c: &State, +) -> FallibleApiResponse { check_auth!(t, c); let days = if let Some(days) = days { - days.parse().map_err(|_| api_error("Invalid days value")).ok() + days.parse() + .map_err(|_| api_error("Invalid days value")) + .ok() } else { None }; - + let t = Transaction::active_expired(days).await; Ok(json!(t)) diff --git a/src/routes/item/stat.rs b/src/routes/item/stat.rs index 7b5bb0b..4da647c 100644 --- a/src/routes/item/stat.rs +++ b/src/routes/item/stat.rs @@ -83,4 +83,4 @@ pub async fn item_stat_route( "total_transactions": transaction_count, "total_price": total_price })) -} \ No newline at end of file +} diff --git a/src/routes/item/supply.rs b/src/routes/item/supply.rs index fdb5f98..afbda10 100644 --- a/src/routes/item/supply.rs +++ b/src/routes/item/supply.rs @@ -130,10 +130,11 @@ pub async fn inventory_route_variant( } /// Returns statistics for the Item Variant -#[get("/item///stat")] +#[get("/item///stat?")] pub async fn variant_stat_route( item_id: &str, variant_id: &str, + full: Option<&str>, itemdb: &State, t: Token, c: &State, @@ -146,5 +147,7 @@ pub async fn variant_stat_route( .variant(variant_id) .ok_or_else(variant_does_not_exist_error)?; - Ok(variant.stat().await) + Ok(variant + .stat(full.map(|x| x == "1" || x == "true").unwrap_or(false)) + .await) } diff --git a/src/transaction.rs b/src/transaction.rs index bffd36e..e74f3ec 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -97,28 +97,45 @@ impl Transaction { pub async fn is_expired_at(&self, time: i64) -> bool { if let Some(expiry) = Item::get(&self.item) - .await - .unwrap() - .variant(&self.variant) - .unwrap() - .expiry - { - let date_added = self.timestamp; + .await + .unwrap() + .variant(&self.variant) + .unwrap() + .expiry + { + let date_added = self.timestamp; - let expiration_ts = expiry * 24 * 60 * 60; + let expiration_ts = expiry * 24 * 60 * 60; - return (date_added + expiration_ts) < time; - } + return (date_added + expiration_ts) < time; + } - false + false } pub async fn is_expired_in_days(&self, days: i64) -> bool { let current_time = chrono::Utc::now().timestamp(); - self.is_expired_at(current_time + (days * 24 * 60 * 60)).await + self.is_expired_at(current_time + (days * 24 * 60 * 60)) + .await } pub async fn is_expired(&self) -> bool { + if self.consumed.is_some() { + if let Some(expiry) = Item::get(&self.item) + .await + .unwrap() + .variant(&self.variant) + .unwrap() + .expiry + { + let time_around = self.timestamp - self.consumed.as_ref().unwrap().timestamp; + let expiration_ts = expiry * 24 * 60 * 60; + return time_around > expiration_ts; + } else { + return false; + } + } + let current_time = chrono::Utc::now().timestamp(); self.is_expired_at(current_time).await } diff --git a/src/variant.rs b/src/variant.rs index 5e02d2e..31bbeee 100644 --- a/src/variant.rs +++ b/src/variant.rs @@ -1,3 +1,6 @@ +use std::collections::HashMap; + +use futures::StreamExt; use mongod::{Model, Sort}; use mongodb::bson::doc; use serde::{Deserialize, Serialize}; @@ -274,15 +277,65 @@ impl Variant { (false, 0) } - pub async fn stat(&self) -> serde_json::Value { + pub async fn stat(&self, full: bool) -> serde_json::Value { let active_transactions = self.inventory().await; // fix : ignores currency let total_price: f64 = active_transactions.iter().map(|x| x.price.value).sum(); + if !full { + return json!({ + "amount": active_transactions.len(), + "total_price": total_price + }); + } + + let all_transactions = Transaction::find( + doc! { "item": &self.item, "variant": &self.variant}, + None, + None, + ) + .await + .unwrap(); + let mut expired_count = 0.0; + + for t in &all_transactions { + if t.is_expired().await { + expired_count += 1.0; + } + } + + let expiry_rate = expired_count / all_transactions.len() as f64; + let mut origin_stat = HashMap::new(); + + for origin in self.get_unique_origins().await { + let transactions_from_origin = active_transactions + .iter() + .filter(|x| x.origin.as_ref().map(|x| *x == origin).unwrap_or(false)) + .collect::>(); + + let prices = self + .price_history_by_origin(&origin, None) + .await + .into_iter() + .map(|x| x.value) + .collect::>(); + let prices_len = prices.len() as f64; + let prices_summed = prices.into_iter().reduce(|acc, e| acc + e).unwrap_or(0.0); + + let stat_json = json!({ + "average_price": prices_summed / prices_len, + "inventory": transactions_from_origin.len() + }); + + origin_stat.insert(origin, stat_json); + } + json!({ - "amount": active_transactions.len(), - "total_price": total_price + "amount": active_transactions.len(), + "total_price": total_price, + "expiry_rate": expiry_rate, + "origins": origin_stat }) }