Repository: IgnisDa/ryot

Issue #73: [FEATURE REQUEST] - Allow Ryot to track anything
Created: 2023-05-27T02:10:14Z
The idea was from Reddit.
Ryot be extended to track other types of items. For example:

I (and many others) need a whisky tracker xD (desired/tasted/owned/planned bottles etc). Some people would want a cigar tracker.
Ideally, there should be a YAML config that one could use to create a tracker for items they need; and a common shared database of such "userconfigs".
Even better, one could provide external APIs in YAMLs for auto-fill.


I do not plan to work on this anytime soon since it would be a big undertaking, and I would like to finish the fitness tracking. But I am creating this issue to gather feedback.

Duplicate issue #865:  [FEATURE REQUEST] - Physical item model proposal
Created: 2024-06-15T01:06:13Z
Hi,
Thanks for open sourcing this project. I am glad to see more open source Rust project and I've seen you actively promote and integrate ryot with other app. So I guess you are open to suggestions.
After taking a glance of the repo, it seems that ryot only able to keep track of virtual items so far. The ability of tracking physical items is missing. For example, if I have 2 bottles of flu medicine.

One is bought in 6 months ago, expired in 2 years, 80% full, stored in 100 tablets bottle, located in home;
and another one is bought in 1 years ago, checked in 2 days ago, expired in 4 months later, 50% full, stored in 50 tablets bottle in office.

Ryot cannot handle case like this, is my understanding correct?

I would like to propose a generic model to handle above cases. Although I am experienced with PgSql, I have not used SeaORM before, so I would just present the DB relation as diagram.
Unlike virtual items, a physical items have attributes shared in common and individual unique attributes. So I suggest we should break down the model as two.

Problem 1) No generic physical item type model for attributes shared in common
Proposal:
pub struct Stock {
    pub id: String,
    pub name: String,
    #[serde(alias = "description")]
    pub overview: Option<String>,
    pub barcode: Option<String>,
    pub url_list: Option<HashMap<String, String>>,
    pub invert_url_list: Option<HashMap<String, String>>,
    #[serde(deserialize_with = "deserialize_date")]
    pub created: NaiveDate,
    #[serde(deserialize_with = "deserialize_date")]
    pub updated: Option<NaiveDate>,
    #[serde(deserialize_with = "deserialize_date")]
    pub deleted: Option<NaiveDate>,
    pub thumbnail: Option<String>,
}


The url_list is for product page, manufactory page, online manual... And the invert_url_list is for other app's integration, just like the back link concept from wiki(https://wikiless.northboot.xyz/wiki/Backlink?lang=en).

Problem 2) No generic physical item instance model for individual unique attributes
Proposal:
pub struct Instance {
    pub id: String,
    pub quantity: i32,
    pub barcode: Option<String>,
    #[serde(deserialize_with = "deserialize_date")]
    pub expired: Option<NaiveDate>,
}

1 Stock <--> N Instance

Since some items' barcode might different on each one, I suggest that we put barcode fields on both Stock and Instance.

Problem 3) No location model for Instance
Proposal:
pub struct Location {
    pub id: String,
    pub name: String,
    pub barcode: Option<String>,
}

M Location <--> N Instance

Hopefully, we can add an new item instance by just scanning the barcode to "input" location and then scanning another barcode to "input" an item instance in one day. The point is no keyboard involved and just fetching data from an DBs by using the barcode.

Problem 4) No flexible tag model for Stock and Instance
Proposal:
pub struct Tag {
    pub id: String,
    pub key: String,
    pub val: Option<String>,
    pub num: Option<i32>,
}

M Stock <--> N Tag
M Instance <--> N Tag
M Location <--> N Tag

In this way, for example, we can store the following criteria:

Tag(name="minAge", num="3") for Stock
Tag(name="maxTemperature", num="-1", val="celsius") for Location
Tag(name="size", num="50", val="ml") for Instance
Tag(name="capacity", num="50", val="percent") for Instance

And query the following criteria:

Tell me any medicine for babies(minAge<=3) which will be expired in next 2 months
Tell me any frozen food which is low in stock (20%)


Problem 5) No operation model for Instance for auditing or tracking purpose
Proposal:
#[derive(EnumIter, DeriveActiveEnum)]
#[sea_orm(rs_type = "i32", db_type = "Integer")]
pub enum OperationType {
    Purchased = 0,
    Sold = 1,
    CheckPrice = 2,
    Verify = 3,
}

pub struct InstanceOperation {
    pub id: String,
    pub price: Option<f32>,
    pub transaction_url: Option<String>,
    #[serde(deserialize_with = "deserialize_date")]
    pub operation_date: Option<NaiveDate>,
}

1 InstanceOperation <--> M Person/Company
M InstanceOperation <--> 1 Instance

In this way, for example, we can store the following criteria:

Purchase milk for $5 from an online store by me a week ago, and the order page is stored in transaction_url
Mary has checked if milk has been expired 2 days ago
Some price tracker app like Huginn, check if your favorite product is on sale and we can see the log thru the link in transaction_url

Thanks for your time to read till here. I think ryot has lots of potential, so I hope my proposal is welcome in here. In this generic way, hopefully :

You don't need to add every inventory type and reduce your work load.
Allow developers to integrate this app better with other apps because they don't have to wait for a specific inventory type exists.

I hope you would consider the above proposal to further release ryot's potential.

Closing comment (2024-06-30T01:56:51Z): duplicates #73 ? Feature-wised, yes.
I took a look for Homebox a while ago. That project is a good one, but
a. The original author archives the repo now. Although someone picks it up, I don't know how long will the project last
b. The original author specific said don't want to support food. hay-kot/homebox#431

If there exists a DB schema is flexible enough to support all, why not? It feels good to have a single inventory for everything. But you are right, may be we just have to fall back to what we can have.