This commit is contained in:
parent
91d39a4d83
commit
16353c7683
8 changed files with 123 additions and 86 deletions
38
docs/Item.md
38
docs/Item.md
|
@ -87,3 +87,41 @@ variants:
|
|||
needs:
|
||||
temperature: [5.0, 10.0]
|
||||
```
|
||||
|
||||
### Quantization
|
||||
Sometimes items are homogenous and can be subdivided.
|
||||
This can be defined via the `unit` of an Item Variant.
|
||||
You define the base unit (the smallest possible instance) of an Item Variant. In this case `ml`.
|
||||
Optionally you can define various `conversions` to bigger units by specifiying the units name and how many of the base unit this unit is.
|
||||
In this case we define `liter` to be 1000 `ml`.
|
||||
|
||||
```yml
|
||||
name: "Water"
|
||||
variants:
|
||||
regular:
|
||||
name: "Regular Water"
|
||||
unit:
|
||||
by: "ml"
|
||||
conversions:
|
||||
liter: 1000
|
||||
```
|
||||
|
||||
### Properties
|
||||
Some items might be more or less the same thing but come in various configurations.
|
||||
To address such items you can define custom properties on Item Variants.
|
||||
You can then use these properties to save and filter on metadata about your items.
|
||||
This can be done by defining custom properties in a JSON schema like format in `properties`:
|
||||
|
||||
```yml
|
||||
name: "iPhone"
|
||||
variants:
|
||||
iphone:
|
||||
name: "iPhone"
|
||||
properties:
|
||||
color:
|
||||
enum: ["Black", "White", "Red"]
|
||||
description: "The Phone Color"
|
||||
ram:
|
||||
type: integer
|
||||
description: "The amount of RAM"
|
||||
```
|
||||
|
|
3
migrations/0002_quanta_properties.sql
Normal file
3
migrations/0002_quanta_properties.sql
Normal file
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE transactions
|
||||
ADD COLUMN quanta BIGINT,
|
||||
ADD COLUMN properties JSONB;
|
|
@ -121,6 +121,8 @@ impl Flow {
|
|||
Some(&format!("flow::{}::{}", self.kind, self.id)),
|
||||
info.location.as_ref().map(|x| x.as_str()),
|
||||
info.note.as_ref().map(|x| x.as_str()),
|
||||
info.quanta,
|
||||
info.properties.clone()
|
||||
)
|
||||
.await;
|
||||
ret.entry(item.item_variant_id().clone())
|
||||
|
|
|
@ -96,7 +96,7 @@ impl Item {
|
|||
for (variant_id, variant) in variants_lst {
|
||||
variants.insert(
|
||||
variant_id.as_str().unwrap().to_string(),
|
||||
Variant::from_yml(&variant, variant_id.as_str().unwrap(), &id),
|
||||
Variant::from_yml(variant, variant_id.as_str().unwrap(), &id),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,10 @@ pub struct Transaction {
|
|||
pub location: Option<String>,
|
||||
/// Notes on Transaction
|
||||
pub note: Option<String>,
|
||||
/// Qantized Unit
|
||||
pub quanta: Option<i64>,
|
||||
/// Custom properties
|
||||
pub properties: Option<serde_json::Value>,
|
||||
/// Timestamp of the Transaction
|
||||
pub created: chrono::DateTime<chrono::Utc>,
|
||||
/// Destination of the Item or who consumed it
|
||||
|
@ -35,6 +39,18 @@ pub struct Transaction {
|
|||
pub consumed_timestamp: Option<chrono::DateTime<chrono::Utc>>,
|
||||
}
|
||||
|
||||
// TODO : typed origins / dests
|
||||
|
||||
pub enum Origin {
|
||||
Flow(String),
|
||||
Custom(String)
|
||||
}
|
||||
|
||||
pub enum Destination {
|
||||
Flow(String),
|
||||
Custom(String)
|
||||
}
|
||||
|
||||
impl Transaction {
|
||||
pub async fn new(
|
||||
item: &str,
|
||||
|
@ -43,14 +59,18 @@ impl Transaction {
|
|||
origin: Option<&str>,
|
||||
location: Option<&str>,
|
||||
note: Option<&str>,
|
||||
quanta: Option<i64>,
|
||||
properties: Option<serde_json::Value>
|
||||
) -> Self {
|
||||
sqlx::query_as("INSERT INTO transactions (item, variant, price, origin, location, note) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *")
|
||||
sqlx::query_as("INSERT INTO transactions (item, variant, price, origin, location, note, quanta, properties) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *")
|
||||
.bind(item)
|
||||
.bind(variant)
|
||||
.bind(price)
|
||||
.bind(origin)
|
||||
.bind(location)
|
||||
.bind(note)
|
||||
.bind(quanta)
|
||||
.bind(properties)
|
||||
.fetch_one(get_pg!()).await.unwrap()
|
||||
}
|
||||
|
||||
|
@ -207,6 +227,8 @@ impl ToAPI for Transaction {
|
|||
"consumed": consumed,
|
||||
"note": self.note,
|
||||
"expired": self.is_expired().await,
|
||||
"properties": self.properties,
|
||||
"quanta": self.quanta
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,16 @@ pub struct Variant {
|
|||
pub barcodes: Option<Vec<i64>>,
|
||||
/// Variant Need Conditions
|
||||
pub needs: Option<VariantNeedCondition>,
|
||||
/// Custom fields as JSON object schema
|
||||
pub meta: Option<serde_json::Value>,
|
||||
/// Quantifiable
|
||||
pub unit: Option<Quanta>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Quanta {
|
||||
pub by: String,
|
||||
pub conversions: HashMap<String, f64>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
|
@ -57,51 +67,8 @@ pub struct VariantNeedCondition {
|
|||
|
||||
impl Variant {
|
||||
/// Create variant from itemdb yaml
|
||||
pub fn from_yml(json: &serde_yaml::Value, variant: &str, item: &str) -> Self {
|
||||
Self {
|
||||
item: item.to_string(),
|
||||
variant: variant.to_string(),
|
||||
name: json
|
||||
.as_mapping()
|
||||
.unwrap()
|
||||
.get("name")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
min: json
|
||||
.as_mapping()
|
||||
.unwrap()
|
||||
.get("min")
|
||||
.map(|x| x.as_i64().unwrap()),
|
||||
expiry: json
|
||||
.as_mapping()
|
||||
.unwrap()
|
||||
.get("expiry")
|
||||
.map(|x| x.as_i64().unwrap()),
|
||||
barcodes: json.as_mapping().unwrap().get("barcodes").map(|x| {
|
||||
x.as_sequence()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|x| x.as_i64().unwrap())
|
||||
.collect()
|
||||
}),
|
||||
needs: json.as_mapping().unwrap().get("needs").map(|x| {
|
||||
let temp_range = x
|
||||
.as_mapping()
|
||||
.unwrap()
|
||||
.get("temperature")
|
||||
.unwrap()
|
||||
.as_sequence()
|
||||
.unwrap();
|
||||
VariantNeedCondition {
|
||||
temperature: [
|
||||
temp_range.get(0).unwrap().as_f64().unwrap(),
|
||||
temp_range.get(1).unwrap().as_f64().unwrap(),
|
||||
],
|
||||
}
|
||||
}),
|
||||
}
|
||||
pub fn from_yml(json: serde_yaml::Value, variant: &str, item: &str) -> Self {
|
||||
serde_yaml::from_value(json).unwrap()
|
||||
}
|
||||
|
||||
/// Get a API id for this Item Variant.
|
||||
|
@ -175,8 +142,10 @@ impl Variant {
|
|||
origin: Option<&str>,
|
||||
location: Option<&str>,
|
||||
note: Option<&str>,
|
||||
quanta: Option<i64>,
|
||||
properties: Option<serde_json::Value>
|
||||
) -> Transaction {
|
||||
Transaction::new(&self.item, &self.variant, price, origin, location, note).await
|
||||
Transaction::new(&self.item, &self.variant, price, origin, location, note, quanta, properties).await
|
||||
}
|
||||
|
||||
/// Returns all Transactions of this Item Variant
|
||||
|
|
|
@ -141,9 +141,7 @@ async fn rocket() -> _ {
|
|||
integrity::verify_integrity(&config, &flows, &locations, &itemdb).await;
|
||||
|
||||
rocket::build()
|
||||
.mount(
|
||||
"/",
|
||||
route![
|
||||
.mount("/", route![
|
||||
routes::item::get_items_route,
|
||||
routes::item::item_route,
|
||||
routes::item::item_variants_page,
|
||||
|
@ -177,8 +175,7 @@ async fn rocket() -> _ {
|
|||
routes::flow::create_flow_note_route,
|
||||
routes::flow::flow_notes_route,
|
||||
routes::item::item_image_route
|
||||
],
|
||||
)
|
||||
])
|
||||
.manage(itemdb)
|
||||
.manage(locations)
|
||||
.manage(flows)
|
||||
|
|
|
@ -21,6 +21,8 @@ pub struct SupplyForm {
|
|||
pub origin: Option<String>,
|
||||
pub location: Option<String>,
|
||||
pub note: Option<String>,
|
||||
pub quanta: Option<i64>,
|
||||
pub properties: Option<serde_json::Value>
|
||||
}
|
||||
|
||||
#[post("/supply", data = "<form>")]
|
||||
|
@ -39,12 +41,16 @@ pub async fn supply_route(
|
|||
.variant(&form.variant)
|
||||
.ok_or_else(variant_does_not_exist_error)?;
|
||||
|
||||
// TODO : check properties schema
|
||||
|
||||
let transaction = variant
|
||||
.supply(
|
||||
form.price,
|
||||
form.origin.as_deref(),
|
||||
form.location.as_deref(),
|
||||
form.note.as_deref(),
|
||||
form.quanta,
|
||||
form.properties.clone()
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue