use mongod::{ derive::{Model, Referencable}, Model, Validate, }; use mongodb::bson::doc; use serde::{Deserialize, Serialize}; use serde_json::json; /// A Transaction of an Item Variant #[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)] pub struct Transaction { /// UUID pub _id: String, /// Associated Item pub item: String, /// Associated Variant pub variant: String, /// Price of obtaining the Item pub price: Price, /// Origin of the Item pub origin: Option, /// Info on consumption of the Item pub consumed: Option, /// Timestamp of the Transaction pub timestamp: i64, } impl Validate for Transaction { async fn validate(&self) -> Result<(), String> { Ok(()) } } /// Information about consumed Items #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Consumed { /// Destination of the Item or who consumed it pub destination: String, /// Price the Item was exported or consumed at pub price: Price, /// Timestamp of Consumption pub timestamp: i64, } impl Transaction { pub fn new(item: &str, variant: &str, price: Price, origin: Option<&str>) -> Self { Self { _id: uuid::Uuid::new_v4().to_string(), item: item.to_string(), variant: variant.to_string(), price, consumed: None, origin: origin.map(|x| x.to_string()), timestamp: chrono::Utc::now().timestamp(), } } /// Consumes the Item with `price` and `destination` pub async fn consume(&mut self, price: Price, destination: &str) { self.update(&json!({ "consumed": Consumed{destination: destination.to_string(),price, timestamp: chrono::Utc::now().timestamp() } })) .await .ok().unwrap() } pub fn api_json(&self) -> serde_json::Value { json!({ "uuid": self._id, "item": self.item, "variant": self.variant, "price": self.price, "origin": self.origin, "timestamp": self.timestamp, "consumed": self.consumed }) } } /// Economic Price #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Price { /// Value of the currency pub value: f64, /// Kind of currency pub currency: String, } impl Price { pub fn new(value: f64, currency: &str) -> Self { Self { value, currency: currency.to_string(), } } fn parse(price: &str) -> Option { let (value, currency) = price.split_once(' ')?; Some(Self { value: value.parse().ok()?, currency: currency.to_string(), }) } } impl TryFrom for Price { type Error = (); fn try_from(value: String) -> Result { Self::parse(&value).ok_or(()) } }