summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/banking/account.rs77
-rw-r--r--src/banking/asset.rs57
-rw-r--r--src/banking/mod.rs61
-rw-r--r--src/main.rs7
-rw-r--r--src/parsers/ini/mod.rs28
-rw-r--r--src/parsers/mod.rs2
-rw-r--r--src/web_frontend/asset.rs61
-rw-r--r--src/web_frontend/balance.rs56
-rw-r--r--src/web_frontend/chart.rs79
-rw-r--r--src/web_frontend/mod.rs24
-rw-r--r--src/web_frontend/transactions.rs22
-rw-r--r--src/web_frontend/util.rs50
12 files changed, 352 insertions, 172 deletions
diff --git a/src/banking/account.rs b/src/banking/account.rs
new file mode 100644
index 0000000..6994bb4
--- /dev/null
+++ b/src/banking/account.rs
@@ -0,0 +1,77 @@
+use parsers::csv::CsvFile;
+
+pub struct Account {
+ pub name : String,
+ pub iban : String,
+ pub transactions : Vec<Transaction>,
+ pub institute : String
+}
+
+impl Account {
+ pub fn new(name : String, iban : String, transactions : Vec<String>, institute : String) -> Account {
+ let mut trans = Vec::new();
+ if institute == "Sparkasse" {
+ // TODO als function/lambda übergeben die konvertierung..
+ for trans_file in transactions {
+ let file = CsvFile::from_file(&trans_file, ";", true);
+ match file {
+ Ok(f) => { let mut tran = Transaction::from_sparkasse_csv_file(f);
+ trans.append(&mut tran);
+ },
+ Err(e) => panic!("account: new: error reading csv transaction file: {}", e)
+ }
+ }
+ }
+ Account { name : name, iban : iban, transactions : trans, institute : institute }
+ }
+}
+
+#[derive(Serialize)]
+#[derive(Clone)]
+pub struct Transaction {
+ pub sender_name : String,
+ pub amount : f32,
+ pub reference : String,
+ pub date : chrono::NaiveDate
+}
+
+impl Transaction {
+ pub fn from_sparkasse_csv_file(file : CsvFile) -> Vec<Transaction> {
+ let mut ret = Vec::new();
+ for line in file.iter() {
+ let mut sender_name_f = String::from("");
+ let mut sender_iban_f = String::from("");
+ let mut amount_f : f32 = 0.0;
+ let mut reference_f = String::from("");
+ let mut date_f = chrono::NaiveDate::parse_from_str("01.01.2019", "%d.%m.%Y").unwrap();
+ match line.get(&String::from("Kontonummer")) {
+ Some(value) => sender_iban_f = value.to_string(),
+ None => println!("missing sender")
+ }
+ match line.get(&String::from("Beguenstigter/Zahlungspflichtiger")) {
+ Some(value) => sender_name_f = value.to_string(),
+ None => println!("missing sender")
+ }
+ match line.get(&String::from("Verwendungszweck")) {
+ Some(value) => reference_f = value.to_string(),
+ None => println!("missing refernce")
+ }
+ match line.get(&String::from("Betrag")) {
+ Some(value) => amount_f = value.parse().unwrap(),
+ None => println!("missing amount")
+ }
+ match line.get(&String::from("Valutadatum")) {
+ Some(value) => {
+ date_f = chrono::NaiveDate::parse_from_str(value, "%d.%m.%y").unwrap();} ,
+ None => println!("missing date")
+ }
+ ret.push(Transaction {
+ sender_name : sender_name_f,
+ amount : amount_f,
+ reference : reference_f,
+ date : date_f });
+
+ }
+ ret
+ }
+}
diff --git a/src/banking/asset.rs b/src/banking/asset.rs
new file mode 100644
index 0000000..7b7287b
--- /dev/null
+++ b/src/banking/asset.rs
@@ -0,0 +1,57 @@
+use crate::banking::account::Account;
+use crate::parsers::ini::IniFile;
+
+pub struct Asset {
+ accounts : Vec<Account>
+}
+
+impl Asset {
+ pub fn from_ini_file(file_name : &str) -> Asset {
+ // read in ini file
+ let t = crate::parsers::ini::IniFile::from_file(file_name);
+ let file;
+ match t {
+ Ok(f) => file = f,
+ Err(e) => panic!("asset: from_ini_file: could not read ini file: {}", e)
+ }
+
+ let mut accounts = Vec::new();
+ for (account_name, config) in file.sections {
+ let mut tmp;
+ match config.get("Institut") {
+ Some(i) => tmp = i,
+ None => panic!("asset: parse ini file: could not find \"Institute\" key for account {}", account_name)
+ }
+ let mut institute = String::from("");
+ if let Some(i) = tmp.get(0) {
+ institute = i.to_string();
+ }
+ let trans_files;
+ match config.get("TransactionFile") {
+ Some(i) => trans_files = i,
+ None => panic!("asset: ini file: no \"TransactionFile\" for account: {}", account_name)
+ }
+ match config.get("IBAN") {
+ Some(i) => tmp = i,
+ None => panic!("asset: no name for account {}", account_name)
+ }
+ let mut iban = String::from("");
+ if let Some(i) = tmp.get(0) {
+ iban = i.to_string();
+ }
+ accounts.push(Account::new(account_name, iban, trans_files.to_vec(), institute));
+
+
+ }
+ Asset { accounts : accounts }
+ }
+
+ pub fn get_account_by_name(self, name : &str) -> Option<Account> {
+ for account in self.accounts {
+ if account.name == name {
+ return Some(account);
+ }
+ }
+ None
+ }
+}
diff --git a/src/banking/mod.rs b/src/banking/mod.rs
index 410bae1..e936286 100644
--- a/src/banking/mod.rs
+++ b/src/banking/mod.rs
@@ -1,59 +1,2 @@
-
-use parsers::csv::CsvFile;
-
-
-pub struct Account {
- name : String,
- iban : String,
- transactions : Vec<Transaction>
-}
-
-
-#[derive(Serialize)]
-pub struct Transaction {
- pub sender_name : String,
- pub amount : f32,
- pub reference : String,
- pub date : chrono::NaiveDate
-}
-
-impl Transaction {
- pub fn from_sparkasse_csv_file(file : CsvFile) -> Vec<Transaction> {
- let mut ret = Vec::new();
- for line in file.iter() {
- let mut sender_name_f = String::from("");
- let mut sender_iban_f = String::from("");
- let mut amount_f : f32 = 0.0;
- let mut reference_f = String::from("");
- let mut date_f = chrono::NaiveDate::parse_from_str("01.01.2019", "%d.%m.%Y").unwrap();
- match line.get(&String::from("Kontonummer")) {
- Some(value) => sender_iban_f = value.to_string(),
- None => println!("missing sender")
- }
- match line.get(&String::from("Beguenstigter/Zahlungspflichtiger")) {
- Some(value) => sender_name_f = value.to_string(),
- None => println!("missing sender")
- }
- match line.get(&String::from("Verwendungszweck")) {
- Some(value) => reference_f = value.to_string(),
- None => println!("missing refernce")
- }
- match line.get(&String::from("Betrag")) {
- Some(value) => amount_f = value.parse().unwrap(),
- None => println!("missing amount")
- }
- match line.get(&String::from("Valutadatum")) {
- Some(value) => {
- date_f = chrono::NaiveDate::parse_from_str(value, "%d.%m.%y").unwrap();} ,
- None => println!("missing date")
- }
- ret.push(Transaction {
- sender_name : sender_name_f,
- amount : amount_f,
- reference : reference_f,
- date : date_f });
-
- }
- ret
- }
-}
+pub mod asset;
+pub mod account;
diff --git a/src/main.rs b/src/main.rs
index 1325742..eef92b6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,10 +20,13 @@ fn main() {
// e.g. wheres is the asset config ini file
// TODO how pass config to the modules/handler ?
// launch web frontend
+ let asset_ini = "data/asset.ini";
+ banking::asset::Asset::from_ini_file(asset_ini);
rocket::ignite()
.attach(Template::fairing())
- .mount("/", routes![web_frontend::account_handler, web_frontend::transactions::transaction_handler,
+ .mount("/", routes![web_frontend::transactions::transaction_handler,
web_frontend::transactions::transaction_handler_post,
- web_frontend::balance::balance_handler, web_frontend::static_handler])
+ web_frontend::balance::balance_handler, web_frontend::static_handler,
+ web_frontend::chart::chart_handler, web_frontend::asset::asset_handler])
.launch();
}
diff --git a/src/parsers/ini/mod.rs b/src/parsers/ini/mod.rs
index 9633231..5095344 100644
--- a/src/parsers/ini/mod.rs
+++ b/src/parsers/ini/mod.rs
@@ -4,17 +4,13 @@ use std::io::BufRead;
use std::collections::HashMap;
pub struct IniFile {
- pub section : HashMap<String, Vec<IniSection>>
-}
-
-pub struct IniSection {
- pub section_name : String,
- pub properties : HashMap<String, Vec<String>>
+ // section_name, key, list of values
+ pub sections : HashMap<String, HashMap<String, Vec<String>>>
}
impl IniFile {
pub fn from_file(path : &str) -> Result<IniFile, io::Error> {
- let mut file = HashMap::new();
+ let mut file : HashMap<String, HashMap<String,Vec<String>>> = HashMap::new();
let fd = File::open(path)?;
let reader = io::BufReader::new(fd);
let mut current_section = String::from("");
@@ -38,7 +34,7 @@ impl IniFile {
}
current_section = n.to_string();
// TODO maybe the sections has been specified twice?
- file.insert(n.to_string(), Vec::new() );
+ file.insert(n.to_string(), HashMap::new() );
continue;
}
@@ -51,10 +47,22 @@ impl IniFile {
if let Some(t) = kv.get(1) {
value = t.to_string();
}
+ println!("key: {}, value: {}", key, value);
if let Some(section) = file.get_mut(&current_section) {
- // get the entry with key from vector
+ println!("found current section");
+ // get the values for key in section current_section
+ let mut hack_first = true;
if let Some(ent) = section.get_mut(&key) {
- ent.insert(value.to_string());
+ println!("found key in map");
+ ent.push(value.to_string());
+ hack_first = false;
+ }
+ if hack_first {
+ let mut new = Vec::new();
+ new.push(value.to_string());
+ section.insert(key, new);
+ // TODO create new HashMap and insert
+ println!("inserted new one");
}
}
}
diff --git a/src/parsers/mod.rs b/src/parsers/mod.rs
index d8bce3c..5c59a19 100644
--- a/src/parsers/mod.rs
+++ b/src/parsers/mod.rs
@@ -1,2 +1,2 @@
pub mod csv;
-//pub mod ini;
+pub mod ini;
diff --git a/src/web_frontend/asset.rs b/src/web_frontend/asset.rs
new file mode 100644
index 0000000..f69f184
--- /dev/null
+++ b/src/web_frontend/asset.rs
@@ -0,0 +1,61 @@
+use std::collections::HashMap;
+use rocket_contrib::templates::Template;
+use crate::parsers::ini::IniFile;
+use crate::parsers::csv::CsvFile;
+
+
+#[derive(Serialize)]
+pub struct AssetContext {
+ accounts : Vec<Account>
+}
+
+#[derive(Serialize)]
+pub struct Account {
+ name : String,
+ category : String,
+ balance : f32
+}
+
+#[get("/asset")]
+pub fn asset_handler() -> rocket_contrib::templates::Template {
+ let asset_file = "data/asset.ini";
+ let asset_config = IniFile::from_file(asset_file);
+ let ini_file;
+ match asset_config {
+ Ok(file) => ini_file = file,
+ Err(e) => panic!("could not read asset file")
+ }
+
+ let mut acc = Vec::new();
+
+ for (account_name, config) in ini_file.sections {
+ let mut category = String::from("");
+ if let Some(cat) = config.get("Category") {
+ if let Some(c) = cat.get(0) {
+ category = c.to_string();
+ }
+ }
+ let mut all_trans = Vec::new();
+ if let Some(transaction_files) = config.get("TransactionFile") {
+ for file in transaction_files {
+ let transactions = CsvFile::from_file(file, ";", true);
+ let mut t : Vec<crate::banking::account::Transaction> ;
+ match transactions {
+ Ok(trans) => t = crate::banking::account::Transaction::from_sparkasse_csv_file(trans),
+ Err(e) => panic!("could not read file {:?}", e)
+ }
+ all_trans.append(& mut t);
+ }
+ }
+ let balance = all_trans.iter().fold(0.0, |acc, x| acc + x.amount).abs();
+ let tmp = Account {
+ name : account_name,
+ category : category.to_string(),
+ balance : balance
+ };
+ acc.push(tmp);
+ }
+
+ let context = AssetContext { accounts : acc };
+ Template::render("asset", context)
+}
diff --git a/src/web_frontend/balance.rs b/src/web_frontend/balance.rs
index 2cbebec..77311b0 100644
--- a/src/web_frontend/balance.rs
+++ b/src/web_frontend/balance.rs
@@ -1,5 +1,5 @@
use parsers::csv::CsvFile;
-use banking::Account;
+use banking::account::Account;
//use parsers::ini::IniFile;
use std::collections::HashMap;
use rocket_contrib::templates::Template;
@@ -10,6 +10,7 @@ use rocket::http::RawStr;
use regex::Regex;
use chrono::{NaiveDate, Utc};
use chrono::Datelike;
+use crate::web_frontend::util;
#[derive(Serialize)]
struct MonthEarnSpend {
@@ -27,53 +28,6 @@ struct BalanceContext {
date_end : String
}
-#[derive(Debug)]
-struct DateRange {
- start_year : i32,
- start_month : u32,
- end_year : i32,
- end_month : u32,
-}
-
-impl DateRange {
- fn new(start : chrono::NaiveDate, end : chrono::NaiveDate) -> DateRange {
- DateRange {
- start_year : start.year(),
- start_month : start.month(),
- end_year : end.year(),
- end_month : end.month(),
- }
- }
-}
-
-impl Iterator for DateRange {
- type Item = chrono::NaiveDate;
-
- fn next(&mut self) -> Option<Self::Item> {
- println!("next called");
- if (self.start_year <= self.end_year) {
- if(self.start_month <= self.end_month) {
- let mut tmp = self.start_year.to_string();
- if self.start_month < 10 {
- tmp.push_str("-0");
- } else {
- tmp.push_str("-");
- }
- tmp.push_str(&self.start_month.to_string());
- tmp.push_str("-01");
- if self.start_month < 13 {
- self.start_month = self.start_month + 1;
- } else {
- self.start_month = 1;
- self.start_year = self.start_year + 1;
- }
- println!("{}", tmp);
- return Some(chrono::NaiveDate::parse_from_str(&tmp, "%Y-%m-%d").unwrap())
- }
- }
- None
- }
-}
#[get("/balance?<start>&<end>")]
pub fn balance_handler(start : Option<&RawStr>, end : Option<&RawStr>) -> rocket_contrib::templates::Template {
@@ -89,14 +43,14 @@ pub fn balance_handler(start : Option<&RawStr>, end : Option<&RawStr>) -> rocket
chrono::NaiveDate::parse_from_str(&tmp, "%Y-%m-%d").unwrap() },
None => Utc::today().naive_utc()
};
- let date_range = DateRange::new(date_start, date_end);
+ let date_range = crate::web_frontend::util::DateRange::new(date_start, date_end);
let mut earn_spend_v = Vec::new();
for date in date_range {
let transactions = CsvFile::from_file("data/t.csv", ";", true);
- let t : Vec<crate::banking::Transaction> ;
+ let t : Vec<crate::banking::account::Transaction> ;
match transactions {
- Ok(trans) => t = crate::banking::Transaction::from_sparkasse_csv_file(trans),
+ Ok(trans) => t = crate::banking::account::Transaction::from_sparkasse_csv_file(trans),
Err(e) => panic!("could not read file {:?}", e)
}
let result : Vec<_> = t.iter().filter(|x| x.date.month() == date.month()).collect();
diff --git a/src/web_frontend/chart.rs b/src/web_frontend/chart.rs
index c5948fe..7065c6d 100644
--- a/src/web_frontend/chart.rs
+++ b/src/web_frontend/chart.rs
@@ -1,6 +1,7 @@
-use parsers::csv::CsvFile;
-use banking::Account;
-//use parsers::ini::IniFile;
+use crate::parsers::csv::CsvFile;
+use crate::banking::account::Account;
+use crate::banking::asset::Asset;
+use crate::parsers::ini::IniFile;
use std::collections::HashMap;
use rocket_contrib::templates::Template;
use rocket::response::NamedFile;
@@ -14,12 +15,29 @@ use chrono::Datelike;
#[derive(Serialize)]
struct ChartContext {
account_name : String,
- groups : HashMap<String, f32>
+ groups : HashMap<String, f32>,
+ total_sum : f32,
+ total_chart : f32,
+ date_start : String,
+ date_end : String
}
-#[get("/chart")]
-fn chart_handler() -> rocket_contrib::templates::Template {
+#[get("/chart?<start>&<end>")]
+pub fn chart_handler(start : Option<&RawStr>, end : Option<&RawStr>) -> rocket_contrib::templates::Template {
+ let date_start = match start {
+ Some(s) => { let mut tmp = s.to_string();
+ tmp.push_str("-01");
+ chrono::NaiveDate::parse_from_str(&tmp, "%Y-%m-%d").unwrap() },
+ None => Utc::today().naive_utc()
+ };
+ let date_end = match end {
+ Some(s) => { let mut tmp = s.to_string();
+ tmp.push_str("-01");
+ chrono::NaiveDate::parse_from_str(&tmp, "%Y-%m-%d").unwrap() },
+ None => Utc::today().naive_utc()
+ };
+ let date_range = crate::web_frontend::util::DateRange::new(date_start, date_end);
// read group config
let chart_file = "data/giro";
let chart_config = IniFile::from_file(chart_file);
@@ -29,33 +47,52 @@ fn chart_handler() -> rocket_contrib::templates::Template {
Err(e) => panic!("could not read group file {:?}", e)
}
let mut groups = HashMap::new();
+
+ let asset_ini = "data/asset.ini";
+ let asset = crate::banking::asset::Asset::from_ini_file(asset_ini);
+ let transactions = asset.get_account_by_name("Girokonto");
+ let acc;
+ match transactions {
+ Some(trans) => acc = trans,
+ None => panic!("could not read file")
+ }
+ let t = acc.transactions;
+ // filter transaction to match only the specified timeframe
+ println!("unfiltered number: {}", t.len());
+ let mut t_filtered = Vec::new();
+ for date in date_range {
+ let mut tmp : Vec<_> = t.iter().filter(|x| x.date.month() == date.month()).collect();
+ t_filtered.append(& mut tmp);
+
+ }
+ println!("filtered number: {}", t_filtered.len());
+ let total_sum = t_filtered.iter().filter(|t| t.amount < 0.0 )
+ .fold(0.0, |acc, x| acc + x.amount).abs();
+ println!("total sum: {}", total_sum);
+ let mut total_chart = 0.0;
for (section_name, entries) in ini_file.sections {
let mut complete = 0.0;
- println!("section name: {}", section_name);
- for entrie in entries {
- for val in entrie.values {
- if entrie.name.is_empty() || val.is_empty() {
+ for (key, values) in entries {
+ for val in values {
+ let mut t_filtered_cloned = t_filtered.clone();
+ if val.is_empty() || val.is_empty() {
continue
}
- println!("entrie is : {}", entrie.name);
- let transactions = CsvFile::from_file("data/t.csv", ";", true);
- let t : Vec<banking::Transaction> ;
- match transactions {
- Ok(trans) => t = banking::Transaction::from_sparkasse_csv_file(trans),
- Err(e) => panic!("could not read file {:?}", e)
- }
- let re = Regex::new(&val).unwrap();
- let tmp = t.into_iter().filter(|transaction|
+ let re = Regex::new(&val).unwrap();
+ let tmp = t_filtered_cloned.into_iter().filter(|transaction|
re.is_match(&transaction.sender_name) )
.fold(0.0, |acc, x| acc + x.amount);
- complete = complete + tmp.abs();
+ complete = complete + tmp.abs();
}
}
groups.insert(section_name, complete);
+ total_chart = total_chart + complete;
// ALSO INSERT OTHER, AKA THE REST
}
let context = ChartContext { account_name : String::from("Girokonto"),
- groups : groups };
+ groups : groups, total_sum : total_sum, total_chart : total_chart,
+ date_start : date_start.to_string()[0..7].to_string(),
+ date_end : date_end.to_string()[0..7].to_string() };
Template::render("chart", context)
}
diff --git a/src/web_frontend/mod.rs b/src/web_frontend/mod.rs
index 8577065..3f58227 100644
--- a/src/web_frontend/mod.rs
+++ b/src/web_frontend/mod.rs
@@ -1,27 +1,13 @@
pub mod transactions;
pub mod balance;
-use parsers::csv::CsvFile;
-use crate::banking::Account;
-//use parsers::ini::IniFile;
-use std::collections::HashMap;
-use rocket_contrib::templates::Template;
+pub mod chart;
+pub mod asset;
+mod util;
use rocket::response::NamedFile;
use std::path::{PathBuf, Path};
-use rocket::request::Form;
-use rocket::http::RawStr;
-use regex::Regex;
-use chrono::{NaiveDate, Utc};
-use chrono::Datelike;
-/*
- * Overview over all accounts, complete asset overview?
- */
-#[get("/")]
-pub fn account_handler() -> rocket_contrib::templates::Template {
- let context : HashMap<u32, u32> = HashMap::new();
- Template::render("account", context)
-}
-// allow always access
+
+// allow always access to static files
#[get("/static/<file..>")]
pub fn static_handler(file: PathBuf) -> Option<NamedFile> {
NamedFile::open(Path::new("static/").join(file)).ok()
diff --git a/src/web_frontend/transactions.rs b/src/web_frontend/transactions.rs
index 417ca96..28e2dd1 100644
--- a/src/web_frontend/transactions.rs
+++ b/src/web_frontend/transactions.rs
@@ -1,5 +1,6 @@
use parsers::csv::CsvFile;
-use crate::banking::Account;
+use crate::banking::account::Account;
+use crate::banking::asset::Asset;
//use parsers::ini::IniFile;
use std::collections::HashMap;
use rocket_contrib::templates::Template;
@@ -22,7 +23,7 @@ use chrono::Datelike;
*/
#[derive(Serialize)]
struct TransactionContext {
- transactions : Vec<crate::banking::Transaction>,
+ transactions : Vec<crate::banking::account::Transaction>,
account_name : String,
filter : String,
date_start : String,
@@ -35,13 +36,16 @@ pub struct TransactionFilter {
}
impl TransactionFilter {
- pub fn apply_filter(&self, transactions : Vec<crate::banking::Transaction>) -> Vec<crate::banking::Transaction> {
- let transactions = CsvFile::from_file("data/t.csv", ";", true);
- let t : Vec<crate::banking::Transaction> ;
+ pub fn apply_filter(&self, transactions : Vec<crate::banking::account::Transaction>) -> Vec<crate::banking::account::Transaction> {
+ let asset_ini = "data/asset.ini";
+ let asset : Asset = crate::banking::asset::Asset::from_ini_file(asset_ini);
+ let transactions = asset.get_account_by_name("Girokonto");
+ let acc;
match transactions {
- Ok(trans) => t = crate::banking::Transaction::from_sparkasse_csv_file(trans),
- Err(e) => panic!("could not read file {:?}", e)
+ Some(trans) => acc = trans,
+ None => panic!("could not read file")
}
+ let t = acc.transactions;
//self.filter.split("=").collect::<Vec<&str>>();
let re = Regex::new(&self.filter).unwrap();
let tmp = t.into_iter().filter(|transaction| re.is_match(&transaction.sender_name) || re.is_match(&transaction.reference) ).collect();
@@ -89,9 +93,9 @@ pub fn transaction_handler(start : Option<&RawStr>, end : Option<&RawStr>) -> ro
None => Utc::today().naive_utc()
};
let transactions = CsvFile::from_file("data/t.csv", ";", true);
- let t : Vec<crate::banking::Transaction> ;
+ let t : Vec<crate::banking::account::Transaction> ;
match transactions {
- Ok(trans) => t = crate::banking::Transaction::from_sparkasse_csv_file(trans),
+ Ok(trans) => t = crate::banking::account::Transaction::from_sparkasse_csv_file(trans),
Err(e) => panic!("could not read file {:?}", e)
}
let context = TransactionContext { transactions: t, account_name : String::from("Girokonto"),
diff --git a/src/web_frontend/util.rs b/src/web_frontend/util.rs
new file mode 100644
index 0000000..cffef0e
--- /dev/null
+++ b/src/web_frontend/util.rs
@@ -0,0 +1,50 @@
+use chrono::{NaiveDate, Utc};
+use chrono::Datelike;
+
+#[derive(Debug)]
+pub struct DateRange {
+ start_year : i32,
+ start_month : u32,
+ end_year : i32,
+ end_month : u32,
+}
+
+impl DateRange {
+ pub fn new(start : chrono::NaiveDate, end : chrono::NaiveDate) -> DateRange {
+ DateRange {
+ start_year : start.year(),
+ start_month : start.month(),
+ end_year : end.year(),
+ end_month : end.month(),
+ }
+ }
+}
+
+impl Iterator for DateRange {
+ type Item = chrono::NaiveDate;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ println!("next called");
+ if (self.start_year <= self.end_year) {
+ if(self.start_month <= self.end_month) {
+ let mut tmp = self.start_year.to_string();
+ if self.start_month < 10 {
+ tmp.push_str("-0");
+ } else {
+ tmp.push_str("-");
+ }
+ tmp.push_str(&self.start_month.to_string());
+ tmp.push_str("-01");
+ if self.start_month < 13 {
+ self.start_month = self.start_month + 1;
+ } else {
+ self.start_month = 1;
+ self.start_year = self.start_year + 1;
+ }
+ println!("{}", tmp);
+ return Some(chrono::NaiveDate::parse_from_str(&tmp, "%Y-%m-%d").unwrap())
+ }
+ }
+ None
+ }
+}