docs + locations
This commit is contained in:
parent
e1618b40ef
commit
48f00d8f6f
17 changed files with 390 additions and 33 deletions
47
Cargo.lock
generated
47
Cargo.lock
generated
|
@ -122,18 +122,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.81"
|
||||
version = "0.1.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
|
||||
checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -302,6 +302,7 @@ dependencies = [
|
|||
"tokio",
|
||||
"toml",
|
||||
"uuid",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -525,7 +526,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version 0.4.1",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -558,7 +559,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"proc-macro2-diagnostics",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -735,7 +736,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1016,9 +1017,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
|
||||
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
|
@ -1440,7 +1441,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"proc-macro2-diagnostics",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1493,7 +1494,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
"version_check",
|
||||
"yansi",
|
||||
]
|
||||
|
@ -1575,7 +1576,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1697,7 +1698,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"rocket_http",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
"unicode-xid",
|
||||
"version_check",
|
||||
]
|
||||
|
@ -1914,7 +1915,7 @@ checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2118,7 +2119,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2140,9 +2141,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.76"
|
||||
version = "2.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2191,7 +2192,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2276,7 +2277,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2373,7 +2374,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2658,7 +2659,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -2680,7 +2681,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
@ -2955,5 +2956,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
|
|
@ -19,3 +19,4 @@ toml = "0.8.8"
|
|||
uuid = { version = "1.8.0", features = ["v4"] }
|
||||
mongod = { git = "https://git.hydrar.de/jmarya/mongod" }
|
||||
env_logger = "0.11.5"
|
||||
walkdir = "2.5.0"
|
||||
|
|
66
docs/Item.md
66
docs/Item.md
|
@ -1,3 +1,67 @@
|
|||
# Item
|
||||
An item is the base concept for CDB. Everything is an Item. An Item describes a general product or object. An item can have multiple variants, beeing the concrete instances of the Item like brand products or different flavors, etc.
|
||||
An item is the base concept for CDB. Everything is an Item. An Item describes a general product or object.
|
||||
|
||||
## Defining an Item
|
||||
An Item is defined within a markdown file with frontmatter. Items are the root dataset of CDB. One can use [this](https://git.hydrar.de/red/itemdb) as a starting point or create their own items.
|
||||
|
||||
For example, we define a "Water" Item:
|
||||
```markdown
|
||||
---
|
||||
name: "Water"
|
||||
variants:
|
||||
common:
|
||||
name: "Common Water"
|
||||
---
|
||||
|
||||
# Water
|
||||
This is a Water Item
|
||||
```
|
||||
|
||||
The file consist of the frontmatter, containing values for the item, and the rest of the markdown file containing a description.
|
||||
|
||||
## Variants
|
||||
Variants are different version of the same item. Each variant can have their own values. Each item needs at least one variant.
|
||||
|
||||
For our water example:
|
||||
```yml
|
||||
name: "Water"
|
||||
variant:
|
||||
regular:
|
||||
name: "Regular Water"
|
||||
sparkling:
|
||||
name: "Sparkling Water"
|
||||
destilled:
|
||||
name: "Destilled Water"
|
||||
```
|
||||
|
||||
Here we have defined three "Water" item variants.
|
||||
|
||||
## Inventory
|
||||
With the items defined, you can start tracking their inventory. See [Transaction](Transaction.md).
|
||||
|
||||
### Min
|
||||
You can set a minimum required inventory for an item variant. This will trigger events when an item reaches a low inventory threshold.
|
||||
|
||||
```yml
|
||||
name: "Water"
|
||||
variants:
|
||||
regular:
|
||||
name: "Regular Water"
|
||||
min: 2
|
||||
```
|
||||
|
||||
This will ensure that at least two units of the "Regular Water" item variant are in inventory.
|
||||
|
||||
### Expiry
|
||||
You can set a default expiry time for an Item Variant. This value is defined as days until expiry.
|
||||
|
||||
```yml
|
||||
name: "Water"
|
||||
variants:
|
||||
regular:
|
||||
name: "Regular Water"
|
||||
expiry: 30
|
||||
```
|
||||
|
||||
This will mark any item variant as expired if it's older than 30 days.
|
||||
|
||||
|
|
56
docs/Location.md
Normal file
56
docs/Location.md
Normal file
|
@ -0,0 +1,56 @@
|
|||
# Location
|
||||
A Location represents a physical location where items can be stored.
|
||||
|
||||
## Defining locations
|
||||
A Location is defined within a JSON file. What a Location represents is up to you. One location can be as specific as individual storage boxes or as general as a whole room. You can even define a hierarchy and additional properties.
|
||||
|
||||
Basic Example: Storage Box
|
||||
```json
|
||||
{
|
||||
"name": "Storage Box"
|
||||
}
|
||||
```
|
||||
|
||||
### Hierarchy
|
||||
You can add a hierarchy to your locations. Let's say for example we have one building we use for storage.
|
||||
|
||||
So we create `storage_building1.json`:
|
||||
```json
|
||||
{
|
||||
"name": "Storage Building"
|
||||
}
|
||||
```
|
||||
|
||||
Then define a room for storage in `storage_room1.json`:
|
||||
```json
|
||||
{
|
||||
"name": "First storage room",
|
||||
"parent": "storage_building1"
|
||||
}
|
||||
```
|
||||
|
||||
The `parent` field here defines that this location is inside another location, therefor setting up a hierarchy from larger scope locations to smaller scope. The `parent` field expects a location ID, which is typically the filename of the JSON without the extension.
|
||||
|
||||
With this we can go even more detailed:
|
||||
```json
|
||||
{
|
||||
"name": "Black Storage Box",
|
||||
"parent": "storage_room1"
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
You can define various properties for a location. This allows for checking the best location for an item based on it's requirements. If locations are in a hierarchy they will inherit the properties of their parents by default.
|
||||
|
||||
#### Conditions
|
||||
Some items might be better stored under certain conditions. You can set the conditions of a location like temperature.
|
||||
|
||||
Example: Freezer
|
||||
```json
|
||||
{
|
||||
"name": "Freezer",
|
||||
"conditions": {
|
||||
"temperature": -10
|
||||
}
|
||||
}
|
||||
```
|
7
docs/README.md
Normal file
7
docs/README.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
# CDB Documentation
|
||||
|
||||
- Item
|
||||
- Location
|
||||
- Statistics
|
||||
- Transaction
|
||||
- Webhooks
|
|
@ -1,2 +1,3 @@
|
|||
# Statistics
|
||||
CDB can create various informational stats based on your dataset.
|
||||
CDB can create various informational stats based on your dataset.
|
||||
#todo
|
|
@ -1,3 +1,17 @@
|
|||
# Transaction
|
||||
A Transaction represents an actual instance of an Item. This is a one to one mapping to a physical Variant of an Item. It can be consumed either manually or by a Process.
|
||||
This makes individual physical goods traceable.
|
||||
A Transaction represents an actual instance of an Item Variant.
|
||||
|
||||
## Supply
|
||||
When you obtain an item and add it to your inventory a Transaction gets created. This is one unit of the item.
|
||||
|
||||
Transactions can carry some information:
|
||||
- Price - The price this item was acquired at
|
||||
- Origin - Where this item is from
|
||||
- Location - The [Location](Location.md) of the item
|
||||
|
||||
## Consume
|
||||
If an item gets used or is removed from the inventory, you consume the transaction.
|
||||
|
||||
This adds some additional information to it:
|
||||
- Price - The price of the item at removal. e.g the selling price, or if negative cost of removal
|
||||
- Destination - Where this item went, e.g a person who requested this item
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
# Webhooks
|
||||
Certain events can trigger webhooks. This allows you to independently build your automation pipeline.
|
||||
Certain events can trigger webhooks. This allows you to independently build your automation pipeline.
|
||||
#todo
|
32
schema/location.json
Normal file
32
schema/location.json
Normal file
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "Location",
|
||||
"description": "A storage location",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Location Name",
|
||||
"description": "The name of the Location"
|
||||
},
|
||||
"parent": {
|
||||
"type": "string",
|
||||
"title": "Parent Location",
|
||||
"description": "The ID of a broader location containing this location."
|
||||
},
|
||||
"conditions": {
|
||||
"type": "object",
|
||||
"title": "Storage Conditions",
|
||||
"description": "The conditions of the storage location.",
|
||||
"properties": {
|
||||
"temperature": {
|
||||
"type": "number",
|
||||
"title": "Temperature",
|
||||
"description": "The median temperature this storage location has."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
]
|
||||
}
|
44
src/json_store.rs
Normal file
44
src/json_store.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
use std::{collections::HashMap, ops::Deref};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
pub struct JSONStore<T> {
|
||||
documents: HashMap<String, T>,
|
||||
}
|
||||
|
||||
impl<T: for<'a> Deserialize<'a>> JSONStore<T> {
|
||||
pub fn new(dir: &str) -> Self {
|
||||
let mut documents = HashMap::new();
|
||||
|
||||
for e in walkdir::WalkDir::new(dir)
|
||||
.into_iter()
|
||||
.filter_map(std::result::Result::ok)
|
||||
{
|
||||
if e.path().is_dir() {
|
||||
continue;
|
||||
}
|
||||
if e.path().extension().is_none() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if e.path().extension().unwrap().to_str().unwrap() == "json" {
|
||||
let path = e.path().to_str().unwrap().to_owned();
|
||||
let file_name = e.path().file_stem().unwrap().to_str().unwrap().to_string();
|
||||
let content = std::fs::read_to_string(path).unwrap();
|
||||
let json = serde_json::from_str(&content).unwrap();
|
||||
|
||||
documents.insert(file_name, json);
|
||||
}
|
||||
}
|
||||
|
||||
Self { documents }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for JSONStore<T> {
|
||||
type Target = HashMap<String, T>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.documents
|
||||
}
|
||||
}
|
70
src/location.rs
Normal file
70
src/location.rs
Normal file
|
@ -0,0 +1,70 @@
|
|||
use mongod::{
|
||||
derive::{Model, Referencable},
|
||||
Model, ToAPI, Validate,
|
||||
};
|
||||
use mongodb::bson::doc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
/// A Storage Location
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)]
|
||||
pub struct Location {
|
||||
/// UUID
|
||||
pub _id: String,
|
||||
/// Name
|
||||
pub name: String,
|
||||
/// Parent
|
||||
pub parent: Option<String>,
|
||||
/// Storage Conditions
|
||||
pub conditions: Option<StorageConditions>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct StorageConditions {
|
||||
/// Median temperature
|
||||
pub temperature: i64,
|
||||
}
|
||||
|
||||
impl Validate for Location {
|
||||
async fn validate(&self) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToAPI for Location {
|
||||
async fn api(&self) -> serde_json::Value {
|
||||
json!({
|
||||
"id": self._id,
|
||||
"name": self.name,
|
||||
"parent": self.parent,
|
||||
"conditions": self.conditions
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Location {
|
||||
pub async fn add(id: &str, o: serde_json::Value) {
|
||||
let l = Location {
|
||||
_id: id.to_string(),
|
||||
name: o
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("name")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
parent: o
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("parent")
|
||||
.map(|x| x.as_str().unwrap().to_string()),
|
||||
conditions: serde_json::from_value(
|
||||
o.as_object().unwrap().get("conditions").unwrap().clone(),
|
||||
)
|
||||
.unwrap(),
|
||||
};
|
||||
|
||||
l.insert_overwrite().await.unwrap();
|
||||
}
|
||||
}
|
13
src/main.rs
13
src/main.rs
|
@ -1,8 +1,15 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use json_store::JSONStore;
|
||||
use location::Location;
|
||||
use mongod::Model;
|
||||
use rocket::routes as route;
|
||||
use rocket::{http::Method, launch};
|
||||
|
||||
mod db;
|
||||
mod item;
|
||||
mod json_store;
|
||||
mod location;
|
||||
mod process;
|
||||
mod routes;
|
||||
mod transaction;
|
||||
|
@ -41,6 +48,11 @@ async fn rocket() -> _ {
|
|||
.expect("error creating CORS options");
|
||||
|
||||
let itemdb = db::ItemDB::new("./itemdb").await;
|
||||
let locations: JSONStore<Location> = JSONStore::new("./locations");
|
||||
|
||||
for location in locations.deref() {
|
||||
location.1.insert_overwrite().await.unwrap();
|
||||
}
|
||||
|
||||
rocket::build()
|
||||
.mount(
|
||||
|
@ -60,5 +72,6 @@ async fn rocket() -> _ {
|
|||
],
|
||||
)
|
||||
.manage(itemdb)
|
||||
.manage(locations)
|
||||
.attach(cors)
|
||||
}
|
||||
|
|
26
src/routes/item/location.rs
Normal file
26
src/routes/item/location.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use mongod::ToAPI;
|
||||
use rocket::{get, State};
|
||||
|
||||
use crate::{
|
||||
json_store::JSONStore,
|
||||
location::Location,
|
||||
routes::{api_error, FallibleApiResponse},
|
||||
};
|
||||
|
||||
#[get("/location/<id>")]
|
||||
pub async fn location_info(
|
||||
id: &str,
|
||||
locations: &State<JSONStore<Location>>,
|
||||
) -> FallibleApiResponse {
|
||||
let loc = locations
|
||||
.get(id)
|
||||
.ok_or_else(|| api_error("No location with that ID"))?;
|
||||
Ok(loc.api().await)
|
||||
}
|
||||
|
||||
#[get("/locations")]
|
||||
pub async fn locations_info(locations: &State<JSONStore<Location>>) -> FallibleApiResponse {
|
||||
// todo : recursive location map
|
||||
|
||||
unimplemented!()
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
mod demand;
|
||||
mod error;
|
||||
mod location;
|
||||
mod supply;
|
||||
|
||||
pub use demand::*;
|
||||
pub use error::*;
|
||||
pub use location::*;
|
||||
use mongod::Model;
|
||||
use mongod::ToAPI;
|
||||
pub use supply::*;
|
||||
|
|
|
@ -16,6 +16,7 @@ pub struct SupplyForm {
|
|||
variant: String,
|
||||
price: String,
|
||||
origin: Option<String>,
|
||||
location: Option<String>,
|
||||
}
|
||||
|
||||
/// Route for supply action. Creates a new Transaction for the specified Item Variant.
|
||||
|
@ -35,6 +36,7 @@ pub async fn supply_route(form: Json<SupplyForm>, itemdb: &State<ItemDB>) -> Fal
|
|||
.try_into()
|
||||
.map_err(|()| api_error("Price malformed"))?,
|
||||
form.origin.as_deref(),
|
||||
form.location.as_deref(),
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use mongod::{
|
||||
assert_reference_of,
|
||||
derive::{Model, Referencable},
|
||||
Model, Validate,
|
||||
reference_of, Model, Referencable, Reference, Validate,
|
||||
};
|
||||
use mongodb::bson::doc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::item::Item;
|
||||
use crate::{item::Item, location::Location};
|
||||
|
||||
/// A Transaction of an Item Variant
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)]
|
||||
|
@ -21,6 +22,8 @@ pub struct Transaction {
|
|||
pub price: Price,
|
||||
/// Origin of the Item
|
||||
pub origin: Option<String>,
|
||||
/// The location of the Item
|
||||
pub location: Option<Reference>,
|
||||
/// Info on consumption of the Item
|
||||
pub consumed: Option<Consumed>,
|
||||
/// Timestamp of the Transaction
|
||||
|
@ -29,6 +32,10 @@ pub struct Transaction {
|
|||
|
||||
impl Validate for Transaction {
|
||||
async fn validate(&self) -> Result<(), String> {
|
||||
if let Some(location) = &self.location {
|
||||
assert_reference_of!(location, Location);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +52,13 @@ pub struct Consumed {
|
|||
}
|
||||
|
||||
impl Transaction {
|
||||
pub fn new(item: &str, variant: &str, price: Price, origin: Option<&str>) -> Self {
|
||||
pub async fn new(
|
||||
item: &str,
|
||||
variant: &str,
|
||||
price: Price,
|
||||
origin: Option<&str>,
|
||||
location: Option<&str>,
|
||||
) -> Self {
|
||||
Self {
|
||||
_id: uuid::Uuid::new_v4().to_string(),
|
||||
item: item.to_string(),
|
||||
|
@ -53,6 +66,11 @@ impl Transaction {
|
|||
price,
|
||||
consumed: None,
|
||||
origin: origin.map(std::string::ToString::to_string),
|
||||
location: if let Some(location) = location {
|
||||
reference_of!(Location, location)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
timestamp: chrono::Utc::now().timestamp(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,8 +142,13 @@ impl Variant {
|
|||
/// # Returns
|
||||
///
|
||||
/// Returns a UUID string representing the transaction.
|
||||
pub async fn supply(&self, price: Price, origin: Option<&str>) -> String {
|
||||
let t = Transaction::new(&self.item, &self.variant, price, origin);
|
||||
pub async fn supply(
|
||||
&self,
|
||||
price: Price,
|
||||
origin: Option<&str>,
|
||||
location: Option<&str>,
|
||||
) -> String {
|
||||
let t = Transaction::new(&self.item, &self.variant, price, origin, location).await;
|
||||
|
||||
t.insert().await.unwrap();
|
||||
|
||||
|
|
Loading…
Reference in a new issue