Ver código fonte

[Categories] Provided account list to category selection functions

Signed-off-by: Slava Barinov <rayslava@gmail.com>
Slava Barinov 4 anos atrás
pai
commit
db8fa71433
5 arquivos alterados com 45 adições e 16 exclusões
  1. 8 3
      src/categories.rs
  2. 15 5
      src/convert.rs
  3. 2 2
      src/main.rs
  4. 11 4
      src/telegram.rs
  5. 9 2
      src/ui.rs

+ 8 - 3
src/categories.rs

@@ -84,10 +84,11 @@ pub fn get_top_category<'a>(item: &str, storage: &'a CatStats) -> Option<&'a str
 pub fn get_category_from_tg(
     item: &str,
     storage: &mut CatStats,
+    accounts: &[String],
     ctx: &UpdateWithCx<AutoSend<Bot>, Message>,
 ) -> String {
     if bot_is_running() {
-        let future = async move { input_category_from_tg(item, &storage, &ctx).await };
+        let future = async move { input_category_from_tg(item, &storage, &accounts, &ctx).await };
         if let Ok(handle) = Handle::try_current() {
             tokio::task::block_in_place(move || handle.block_on(future))
         } else {
@@ -99,14 +100,18 @@ pub fn get_category_from_tg(
 }
 
 /// Choose proper category or ask user
-pub fn get_category(item: &str, storage: &mut CatStats) -> String {
+pub fn get_category(item: &str, storage: &mut CatStats, accounts: &[String]) -> String {
     let istty = unsafe { isatty(libc::STDOUT_FILENO as i32) } != 0;
     if istty {
         let topcat = match get_top_category(item, storage) {
             Some(cat) => String::from(cat),
             None => String::new(),
         };
-        let cat = input_category(item, &topcat);
+        let cats: Vec<&String> = accounts
+            .iter()
+            .filter(|acc| acc.contains("Expense:"))
+            .collect();
+        let cat = input_category(item, &topcat, &cats);
         if cat.is_empty() {
             topcat
         } else {

+ 15 - 5
src/convert.rs

@@ -31,16 +31,21 @@ mod tests {
 }
 
 /// Generate set of QIF Splits from a Purchase items
-pub fn gen_splits<F>(items: &[receipt::Item], cs: &mut CatStats, categorizer: F) -> Vec<Split>
+pub fn gen_splits<F>(
+    items: &[receipt::Item],
+    cs: &mut CatStats,
+    accounts: &[String],
+    categorizer: F,
+) -> Vec<Split>
 where
-    F: Fn(&str, &mut CatStats) -> String,
+    F: Fn(&str, &mut CatStats, &[String]) -> String,
 {
     let mut result: Vec<Split> = Vec::new();
     for i in items.iter() {
         let t = Split::new()
             .memo(i.name.as_str())
             .amount(-i.sum)
-            .category(&categorizer(i.name.as_str(), cs))
+            .category(&categorizer(i.name.as_str(), cs, accounts))
             .build();
 
         result.push(t);
@@ -101,9 +106,14 @@ pub fn convert<'a, F>(
     categorizer: F,
 ) -> Result<Transaction<'a>, String>
 where
-    F: Fn(&str, &mut CatStats) -> String,
+    F: Fn(&str, &mut CatStats, &[String]) -> String,
 {
     let purchase = read_file(filename);
-    let splits = gen_splits(&purchase.items, &mut user.catmap, categorizer);
+    let splits = gen_splits(
+        &purchase.items,
+        &mut user.catmap,
+        &user.accounts,
+        categorizer,
+    );
     gen_trans(&acc, purchase.date(), purchase.total_sum(), memo, splits)
 }

+ 2 - 2
src/main.rs

@@ -69,8 +69,8 @@ fn main() {
         .build();
 
     if let Some(filename) = &args.filename {
-        let cat = &|item: &str, stats: &mut categories::CatStats| -> String {
-            categories::get_category(&item, stats)
+        let cat = &|item: &str, stats: &mut categories::CatStats, acc: &[String]| -> String {
+            categories::get_category(&item, stats, acc)
         };
         let t = convert::convert(filename, &args.memo, &mut user, &acc, &cat).unwrap();
         print!("{}", acc.to_string());

+ 11 - 4
src/telegram.rs

@@ -83,7 +83,7 @@ async fn convert_file(
     log::info!("Got file");
     for i in non_cat_items(&jsonfile, &user) {
         log::info!("Message about {}", i);
-        let newcat = input_category_from_tg(&i, &user.catmap, &ctx).await;
+        let newcat = input_category_from_tg(&i, &user.catmap, &user.accounts, &ctx).await;
         ctx.answer(format!("{} is set to {}", i, newcat))
             .await
             .unwrap();
@@ -93,8 +93,9 @@ async fn convert_file(
         .account_type(AccountType::Cash)
         .build();
 
-    let cat =
-        &|item: &str, stats: &mut CatStats| -> String { get_category_from_tg(&item, stats, &ctx) };
+    let cat = &|item: &str, stats: &mut CatStats, accounts: &[String]| -> String {
+        get_category_from_tg(&item, stats, accounts, &ctx)
+    };
     let t = convert(jsonfile, "Test", user, &acc, cat)?;
     file.write(acc.to_string().as_bytes()).await?;
     file.write(t.to_string().as_bytes()).await?;
@@ -109,10 +110,16 @@ pub fn bot_is_running() -> bool {
 #[cfg(feature = "telegram")]
 pub async fn input_category_from_tg(
     item: &str,
-    categories: &CatStats,
+    _cats: &CatStats,
+    accounts: &[String],
     ctx: &UpdateWithCx<AutoSend<Bot>, Message>,
 ) -> String {
+    log::info!("{:?}", accounts);
+    let keyboard = InlineKeyboardMarkup::default().append_row(accounts.iter().map(|line| {
+        InlineKeyboardButton::new(line, InlineKeyboardButtonKind::CallbackData(line.into()))
+    }));
     ctx.answer(format!("Input category for {}", item))
+        .reply_markup(ReplyMarkup::InlineKeyboard(keyboard))
         .await
         .unwrap();
     String::new()

+ 9 - 2
src/ui.rs

@@ -19,9 +19,16 @@ pub fn run_tv() {
     println!("Hello, world!");
 }
 
-pub fn input_category(item: &str, cat: &str) -> String {
+pub fn input_category(item: &str, cat: &str, cats: &[&String]) -> String {
     let mut x = String::with_capacity(64);
-    print!("'{}'? (default: {}) > ", item, cat);
+    if !cat.is_empty() {
+        print!("'{}'? (default: {}) > ", item, cat);
+    } else {
+        print!(
+            "'{}'? (no default, possible categories: {:?}) > ",
+            item, cats
+        );
+    }
     let _ = stdout().flush();
     stdin().read_line(&mut x).expect("Error reading input");
     String::from(x.trim_end_matches('\n'))