koffice: add scaffold for invoice tool

wip/yesman
Katharina Fey 3 years ago
parent 76799d3bd6
commit c9baaae7cd
Signed by: kookie
GPG Key ID: 90734A9E619C8A6C
  1. 20
      apps/koffice/Cargo.lock
  2. 4
      apps/koffice/invoice/src/base.rs
  3. 52
      apps/koffice/invoice/src/cli.rs
  4. 52
      apps/koffice/invoice/src/main.rs
  5. 7
      apps/koffice/invoice/src/pfile.rs

@ -83,6 +83,17 @@ dependencies = [
"vec_map",
]
[[package]]
name = "colored"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
dependencies = [
"atty",
"lazy_static",
"winapi",
]
[[package]]
name = "dtoa"
version = "0.4.7"
@ -135,6 +146,12 @@ dependencies = [
"serde",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.86"
@ -146,6 +163,9 @@ name = "libko"
version = "1.0.0"
dependencies = [
"chrono",
"colored",
"env_logger",
"log",
"logos",
"serde",
"serde_yaml",

@ -4,6 +4,10 @@ use libko::*;
use std::path::PathBuf;
pub fn init(pid: Option<&str>, tf: Option<&str>, t: Option<&str>, rev: Option<&str>) -> Meta {
if let Some(_) = rev {
eprintln!("--rev parameter currently ignored");
}
let mut meta = initialise();
meta.project_id = pid.map(Into::into);

@ -10,6 +10,7 @@ pub enum Command {
Init,
Generate,
Install,
Set(String, Option<String>),
}
pub fn parse() -> AppState {
@ -42,34 +43,75 @@ pub fn parse() -> AppState {
.settings(&[
AppSettings::SubcommandRequired,
AppSettings::GlobalVersion,
AppSettings::ColoredHelp,
AppSettings::DontCollapseArgsInUsage,
])
.subcommand(
SubCommand::with_name("init")
.about("Initialise a new invoice config")
.arg(project_id.clone())
.arg(timefile)
.arg(revision.clone()),
)
.subcommand(
SubCommand::with_name("generate")
.about("Generate an invoice PDF for a client/ project based on a template")
.arg(project_id)
.arg(revision)
.arg(template),
)
.subcommand(
SubCommand::with_name("set")
.about("Set a variable in the k-office configuration")
.arg(
Arg::with_name("key")
.required(true)
.takes_value(true)
.help("The configuration key to set"),
)
.arg(
Arg::with_name("value")
.takes_value(true)
.help("The value to set the key to. Missing value deletes the key"),
),
);
let matches = app.get_matches();
let project_id = matches.value_of("project id");
let timefile = matches.value_of("timefile");
let template = matches.value_of("template");
let revision = matches.value_of("revision");
let project_id = match matches.subcommand() {
("init", Some(vals)) => vals.value_of("project id"),
("generate", Some(vals)) => vals.value_of("project id"),
_ => None,
};
let timefile = match matches.subcommand() {
("init", Some(vals)) => vals.value_of("timefile"),
("generate", Some(vals)) => vals.value_of("timefile"),
_ => None,
};
let template = match matches.subcommand() {
("init", Some(vals)) => vals.value_of("template"),
("generate", Some(vals)) => vals.value_of("template"),
_ => None,
};
let revision = match matches.subcommand() {
("init", Some(vals)) => vals.value_of("revision"),
("generate", Some(vals)) => vals.value_of("revision"),
_ => None,
};
let (key, value) = match matches.subcommand() {
("set", Some(vals)) => (vals.value_of("key"), vals.value_of("value")),
_ => (None, None),
};
AppState {
meta: crate::base::init(project_id, timefile, template, revision),
cmd: match matches.subcommand() {
("init", _) => Command::Init,
("generate", _) => Command::Generate,
("set", _) => Command::Set(key.unwrap().into(), value.map(Into::into)),
_ => unreachable!(),
},
}

@ -1,3 +1,9 @@
//! A simple invoice generator script
#![allow(warnings)]
#[macro_use] extern crate log;
#[macro_use] extern crate libko;
mod base;
mod cli;
@ -7,35 +13,53 @@ pub(crate) use base::*;
pub(crate) use cli::*;
pub(crate) use pfile::*;
use env_logger::Builder;
use libko::*;
use std::{io::Write, fs::OpenOptions as Oo};
use std::{fs::OpenOptions as Oo, io::Write};
fn main() {
log_util::initialise();
let AppState { meta, cmd } = cli::parse();
match cmd {
Command::Init => init(meta),
Command::Generate => generate(meta),
Command::Install => todo!(),
Command::Set(k, v) => set(meta, k, v),
}
}
/// Initialise a new project invoice with a a metadata set
fn init(meta: Meta) {
let pid = meta.project_id.as_ref().unwrap_or_else(|| {
meta.timefile
.as_ref()
.expect("No project id given, with no timefile available")
.client()
.as_ref()
.unwrap()
});
let pid = meta
.project_id
.as_ref()
.unwrap_or_else(|| match meta.timefile.as_ref() {
Some(tf) => match tf.client().as_ref() {
Some(c) => c,
None => fatal!("No project id given; timefile has no 'project' key!"),
},
None => fatal!("No project id given; no timefile available"),
});
let path = meta.invoice_dir.join(pid);
let mut f = Oo::new().write(true).truncate(true).open(path).unwrap();
f.write_all(pfile::data_templ().as_bytes()).unwrap();
// let pid = meta.project_id.as_ref().unwrap_or_else(||
// let f = meta.invoice_dir.join(meta.project_id);
let invoice_id = meta.new_invoice_id();
// let mut f = match Oo::new().write(true).truncate(true).open(path.clone()) {
// Ok(f) => f,
// _ => fatal!(
// "Failed to create directory {}",
// path.to_str().expect("Path contained non UTF-8 :(")
// ),
// };
// f.write_all(pfile::data_templ(&meta).as_bytes()).unwrap();
}
fn generate(meta: Meta) {}
fn set(meta: Meta, k: String, v: Option<String>) {
meta.update_config(k, v);
}

@ -1,4 +1,4 @@
use crate::{Account, Address, Worker, InvoiceId};
use crate::{Meta, Account, Address, Worker, InvoiceId};
use chrono::NaiveDate;
use serde::{Serialize, Deserialize};
@ -27,7 +27,8 @@ pub enum ServiceEntry {
}
}
pub fn data_templ() -> String {
pub fn data_templ(meta: &Meta) -> String {
let invoice_id = meta.new_invoice_id();
todo!()
}

Loading…
Cancel
Save