Compare commits

..

No commits in common. "58206d41b58a26abbbd6a6c49cfde05c97f20620" and "c1e63fa7617246a61ab208d5c52f0901c9d9e1f2" have entirely different histories.

11 changed files with 60 additions and 129 deletions

View file

@ -47,7 +47,7 @@ ring-compat = { version = "^0.8", features = [
"signature", "signature",
"rand_core", "rand_core",
], optional = true } ], optional = true }
sqlx = { version = "^0.8", features = ["sqlite", "runtime-tokio"], optional = true } sqlx = { version = "^0.8", features = ["sqlite"], optional = true }
tauri = { version = "2", features = ["config-toml"], optional = true } tauri = { version = "2", features = ["config-toml"], optional = true }
tauri-plugin-fs = { version = "2", optional = true } tauri-plugin-fs = { version = "2", optional = true }
tauri-plugin-opener = { version = "2", optional = true } tauri-plugin-opener = { version = "2", optional = true }

View file

@ -1,5 +1,5 @@
"$schema" = "https://schema.tauri.app/config/2" "$schema" = "https://schema.tauri.app/config/2"
identifier = "de.hessensagtnein.darmstadt.buchhaltung" identifier = "de.mathebau.bkbh"
productName = "Nein!" productName = "Nein!"
version = "0.1.0" version = "0.1.0"

View file

@ -16,10 +16,10 @@ val tauriProperties = Properties().apply {
android { android {
compileSdk = 34 compileSdk = 34
namespace = "de.hessensagtnein.darmstadt.buchhaltung" namespace = "de.mathebau.bkbh"
defaultConfig { defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false" manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "de.hessensagtnein.darmstadt.buchhaltung" applicationId = "de.mathebau.bkbh"
minSdk = 24 minSdk = 24
targetSdk = 34 targetSdk = 34
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()

View file

@ -1,29 +0,0 @@
CREATE TABLE `swap` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`acc` INTEGER NOT NULL,
`voucher` INTEGER NOT NULL,
`storno` INTEGER NOT NULL,
`timestamp` INTEGER NOT NULL
);
CREATE TABLE `voucher_type` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`store` INTEGER NOT NULL,
`value` INTEGER NOT NULL,
UNIQUE (`store`, `value`)
);
CREATE TABLE `inventory` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`acc` INTEGER NOT NULL,
`cash` INTEGER NOT NULL,
`timestamp` INTEGER NOT NULL,
UNIQUE (`acc`, `timestamp`)
);
CREATE TABLE `voucher_inventory` (
`inventory` INTEGER NOT NULL,
`voucher` INTEGER NOT NULL,
`count` INTEGER NOT NULL,
PRIMARY KEY (`inventory`, `voucher`)
);

View file

@ -25,6 +25,7 @@ pub fn run() {
}) })
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
server::swap, server::swap,
server::count,
server::inventory, server::inventory,
server::data_door::pull_data, server::data_door::pull_data,
server::data_door::push_data, server::data_door::push_data,

View file

@ -12,7 +12,7 @@ pub struct AppState {
impl AppState { impl AppState {
pub fn new() -> Self { pub fn new() -> Self {
todo!(); todo!()
let db = unimplemented!(); let db = unimplemented!();
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let last_sync = i64::MIN; let last_sync = i64::MIN;

View file

@ -11,10 +11,6 @@ pub mod data_door;
use app_state::AppState; use app_state::AppState;
struct Id {
id: i64,
}
fn parse_inventory(data: HashMap<String, String>) -> Result<Inventory, ()> { fn parse_inventory(data: HashMap<String, String>) -> Result<Inventory, ()> {
let a = data.get("cafe-inventory-acc").ok_or(())?; let a = data.get("cafe-inventory-acc").ok_or(())?;
let acc: Account = Account::try_from(a.as_ref())?; let acc: Account = Account::try_from(a.as_ref())?;
@ -28,13 +24,11 @@ fn parse_inventory(data: HashMap<String, String>) -> Result<Inventory, ()> {
None => (), None => (),
Some(c) => { Some(c) => {
let c = if c == "" { "0" } else { c }; let c = if c == "" { "0" } else { c };
let Ok(count): Result<i64, _> = c.parse() else { let Ok(count) = c.parse() else {
println!("Invalid count '{}' for '{}' in inventory data.", c, s); println!("Invalid count '{}' for '{}' in inventory data.", c, s);
continue; continue;
}; };
let value = 50_00; let v = VoucherInventory { store, count };
let voucher = VoucherType { store, value };
let v = (voucher, count);
vouchers.push(v); vouchers.push(v);
} }
} }
@ -42,28 +36,6 @@ fn parse_inventory(data: HashMap<String, String>) -> Result<Inventory, ()> {
unimplemented!() unimplemented!()
} }
pub async fn voucher_id(v: VoucherType, db: &mut Connection) -> Result<i64, ()> {
sqlx::query!(
"INSERT OR IGNORE INTO voucher_type(store, value) VALUES (?1, ?2)",
v.store,
v.value,
)
.execute(&mut *db)
.await
.map_err(|e| println!("{:?}", e))?;
let id = sqlx::query_as!(
Id,
"SELECT id FROM voucher_type WHERE store = ?1 AND value = ?2",
v.store,
v.value,
)
.fetch_one(db)
.await
.map_err(|e| println!("{:?}", e))?
.id;
Ok(id)
}
#[tauri::command] #[tauri::command]
pub async fn inventory( pub async fn inventory(
data: HashMap<String, String>, data: HashMap<String, String>,
@ -71,37 +43,13 @@ pub async fn inventory(
) -> Result<(), ()> { ) -> Result<(), ()> {
println!("{:?}", data); println!("{:?}", data);
let now = Utc::now().timestamp(); let now = Utc::now().timestamp();
let mut state = state.lock().await; let state = state.lock().await;
let inv = parse_inventory(data)?; let inv = parse_inventory(data)?;
sqlx::query!( for v in inv.vouchers {
"INSERT INTO inventory(acc, cash, timestamp) VALUES (?1, ?2, ?3)", state.db.execute(
inv.acc, "INSERT INTO voucher_inventory VALUES ()",
inv.cash, (inv.acc, v.store, v.count, now),
now,
)
.execute(&mut state.db)
.await
.map_err(|e| println!("{:?}", e))?;
let inventory = sqlx::query_as!(
Id,
"SELECT id FROM inventory WHERE acc = ?1 AND timestamp = ?2",
inv.acc,
now,
)
.fetch_one(&mut state.db)
.await
.map_err(|e| println!("{:?}", e))?
.id;
for (v, count) in inv.vouchers {
let voucher = voucher_id(v, &mut state.db).await?;
sqlx::query!(
"INSERT INTO voucher_inventory VALUES (?1, ?2, ?3)",
inventory,
voucher,
count,
) )
.execute(&mut state.db)
.await
.map_err(|e| println!("{:?}", e))?; .map_err(|e| println!("{:?}", e))?;
} }
Ok(()) Ok(())
@ -113,21 +61,36 @@ pub async fn swap(
acc: i64, acc: i64,
state: State<'_, Mutex<AppState>>, state: State<'_, Mutex<AppState>>,
) -> Result<(), ()> { ) -> Result<(), ()> {
let timestamp = Utc::now().timestamp(); let state = state.lock().await;
let mut state = state.lock().await; state.db.execute(
let id = i64::from_ne_bytes(state.id.to_ne_bytes()); "INSERT INTO swap VALUES (?1, ?2, ?3, ?4, ?5)",
let value = 50_00; (
let voucher = VoucherType{ store, value }; store,
let voucher_type = voucher_id(voucher, &mut state.db).await?; acc,
sqlx::query!( i64::from_ne_bytes(state.id.to_ne_bytes()),
"INSERT INTO swap(acc, voucher, storno, timestamp) VALUES (?1, ?2, ?3, ?4)", Utc::now().timestamp(),
acc, false,
voucher_type, ),
false,
timestamp,
) )
.execute(&mut state.db)
.await
.map_err(|e| println!("{:?}", e))?; .map_err(|e| println!("{:?}", e))?;
Ok(()) Ok(())
} }
#[tauri::command]
pub async fn count(state: State<'_, Mutex<AppState>>) -> Result<String, ()> {
let state = state.lock().await;
let mut stmt =
state.db.prepare_with("SELECT COUNT(*) FROM swap")
.map_err(|e| println!("{:?}", e))?;
let mut rows = stmt.query([]).map_err(|e| println!("{:?}", e))?;
let row = rows.next().map_err(|e| println!("{:?}", e))?;
let row = match row {
Some(r) => Ok(r),
None => {
println!("No rows");
Err(())
}
}?;
let cnt: u64 = row.get(0).map_err(|e| println!("{:?}", e))?;
Ok(cnt.to_string())
}

View file

@ -1,11 +1,10 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "server", derive(sqlx::Type))] #[cfg_attr(features = "dep:sqlx", derive(sqlx::Type))]
#[cfg_attr(feature = "server", repr(i64))]
pub enum Account { pub enum Account {
Sumpf = 1, Sumpf,
Heinersyndikat = 2, Heinersyndikat,
} }
impl TryFrom<&str> for Account { impl TryFrom<&str> for Account {
@ -37,4 +36,4 @@ impl std::fmt::Display for Account {
} }
.fmt(f) .fmt(f)
} }
} }

View file

@ -4,8 +4,6 @@ use serde::{Deserialize, Serialize};
/// measured as an integer multiple /// measured as an integer multiple
/// of 0.01 €. /// of 0.01 €.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "server", derive(sqlx::Type))]
#[cfg_attr(feature = "server", sqlx(transparent))]
pub struct Cash(i64); pub struct Cash(i64);
impl std::str::FromStr for Cash { impl std::str::FromStr for Cash {
@ -22,4 +20,4 @@ impl std::str::FromStr for Cash {
}; };
Ok(Cash(i * 100 + f)) Ok(Cash(i * 100 + f))
} }
} }

View file

@ -8,15 +8,15 @@ pub use store::Store;
pub use account::Account; pub use account::Account;
pub use cash::Cash; pub use cash::Cash;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VoucherType {
pub store: Store,
pub value: i64,
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Inventory { pub struct Inventory {
pub acc: Account, pub acc: Account,
pub cash: Cash, pub cash: Cash,
pub vouchers: Vec<(VoucherType, i64)>, pub vouchers: Vec<VoucherInventory>,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct VoucherInventory {
pub store: Store,
pub count: i64,
} }

View file

@ -2,14 +2,13 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "server", derive(sqlx::Type))] #[cfg_attr(feature = "server", derive(sqlx::Type))]
#[cfg_attr(feature = "server", repr(i64))]
pub enum Store { pub enum Store {
Aldi = 1, Aldi,
Edeka = 2, Edeka,
Dm = 3, Dm,
Lidl = 4, Lidl,
Rewe = 5, Rewe,
Tegut = 6, Tegut,
} }
impl Into<String> for &Store { impl Into<String> for &Store {