Compare commits

..

No commits in common. "main" and "1.0.0" have entirely different histories.
main ... 1.0.0

5 changed files with 26 additions and 210 deletions

View file

@ -1,11 +1,10 @@
[package] [package]
name = "statement-converter" name = "example"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
pdf-extract = "0.9.0" pdf-extract = "0.9.0"
walkdir = "2.5.0"
colored = "3.0.0" colored = "3.0.0"
clap = "4.5.36" clap = "4.5.36"
csv = "1.3.1" csv = "1.3.1"

View file

@ -1,19 +1,10 @@
// Libraries // Libraries
use clap::{Arg, ArgAction, Command}; use clap::{Arg, ArgAction, Command};
// Enums
pub enum ArgModes {
Convert,
Package,
}
// Structures // Structures
pub struct Arguments { pub struct Arguments {
pub mode: ArgModes,
pub file_input: String, pub file_input: String,
pub file_output: String, pub file_output: String,
pub csv_directory: String,
} }
// Implementations // Implementations
@ -24,98 +15,36 @@ impl Arguments {
let matches = Command::new("statement-converter") let matches = Command::new("statement-converter")
.about("A service that converts Bank Statement PDF files into CSV files") .about("A service that converts Bank Statement PDF files into CSV files")
.version("1.0.0") .version("1.0.0")
.subcommand_required(true)
.arg_required_else_help(true) .arg_required_else_help(true)
/* /*
-- Convert Mode PDF Path
*/ */
.subcommand(
Command::new("convert")
.short_flag('c')
.long_flag("convert")
.about("Converts PDF Statements to CSV Files")
.arg( .arg(
Arg::new("file_in") Arg::new("file_in")
.id("file_in") .short('i')
.long("file_in")
.help("The PDF you want to convert") .help("The PDF you want to convert")
.action(ArgAction::Set) .action(ArgAction::Set)
.required(true), .required(true),
) )
.arg( .arg(
Arg::new("file_out") Arg::new("file_out")
.id("file_out") .short('o')
.long("file_out")
.help("The CSV Path you want to save to") .help("The CSV Path you want to save to")
.action(ArgAction::Set) .action(ArgAction::Set)
.required(true), .required(true),
),
)
.subcommand(
Command::new("package")
.short_flag('p')
.long_flag("package")
.about("Combines all CSV Files in a given directory into one MASSIVE one")
.arg(
Arg::new("directory")
.id("directory")
.help("The path where your CSV files are")
.action(ArgAction::Set)
.required(true),
)
.arg(
Arg::new("file_out")
.id("file_out")
.help("The path where the master CSV is saved")
.action(ArgAction::Set)
.required(true),
),
) )
.get_matches(); .get_matches();
// Getting required arguments // Getting the required arguments
let mode: ArgModes; let file_input = matches.get_one::<String>("file_in").unwrap().to_string();
let file_output = matches.get_one::<String>("file_out").unwrap().to_string();
let file_input: String;
let file_output: String;
let csv_directory: String;
// Getting the mode being run
match matches.subcommand() {
Some(("convert", convert_matches)) => {
mode = ArgModes::Convert;
file_input = convert_matches
.get_one::<String>("file_in")
.unwrap()
.to_owned();
file_output = convert_matches
.get_one::<String>("file_out")
.unwrap()
.to_owned();
csv_directory = String::new();
}
Some(("package", package_matches)) => {
mode = ArgModes::Package;
csv_directory = package_matches
.get_one::<String>("directory")
.unwrap()
.to_owned();
file_output = package_matches
.get_one::<String>("file_out")
.unwrap()
.to_owned();
file_input = String::new();
}
_ => unreachable!(),
}
// Returning a Result // Returning a Result
Self { Self {
mode,
file_input, file_input,
file_output, file_output,
csv_directory,
} }
} }
} }

View file

@ -1,22 +1,23 @@
// Libraries // Libraries
mod action; mod action;
mod args; mod args;
mod packager;
mod parser; mod parser;
mod printer; mod printer;
mod reader; mod reader;
mod writer; mod writer;
use args::Arguments; use args::Arguments;
use packager::Packager;
use parser::Parser; use parser::Parser;
use reader::Reader; use reader::Reader;
use writer::Writer; use writer::Writer;
use std::io::Result; use std::io::Result;
// Functions // Entry-Point
fn convert(args: &Arguments) -> Result<()> { fn main() -> Result<()> {
// Reading the Arguments
let args = Arguments::new();
// Display Status // Display Status
printer::print_generic("📃", "Extracting Text"); printer::print_generic("📃", "Extracting Text");
@ -42,31 +43,6 @@ fn convert(args: &Arguments) -> Result<()> {
printer::print_generic("🏁", "Successful Converting Job"); printer::print_generic("🏁", "Successful Converting Job");
printer::print_generic("😎", "Thank you for using Statement Converter!"); printer::print_generic("😎", "Thank you for using Statement Converter!");
// Ok!
Ok(())
}
fn package(args: &Arguments) -> Result<()> {
// Creating a Packager
let packager = Packager::new(args.csv_directory.clone(), args.file_output.clone());
// Starting it
packager.start()?;
// Ok!!
Ok(())
}
// Entry-Point
fn main() -> Result<()> {
// Reading the Arguments
let args = Arguments::new();
// What mode are we in?
match args.mode {
args::ArgModes::Convert => convert(&args)?,
args::ArgModes::Package => package(&args)?,
}
// It's ok! // It's ok!
Ok(()) Ok(())
} }

View file

@ -1,88 +0,0 @@
// Libraries
use std::fs::File;
use std::io::Result;
use csv::{self, StringRecord};
use walkdir::WalkDir;
// Structures
pub struct Packager {
directory: String,
file_out: String,
}
// Implementations
impl Packager {
// Constructors
pub fn new(directory: String, file_out: String) -> Self {
Self {
directory,
file_out,
}
}
// Functions
fn read_csv(&self, path: &str) -> Result<Vec<StringRecord>> {
// Opening the File & Reading
let file = File::open(path)?;
let mut rdr = csv::Reader::from_reader(file);
// Creating a list of string records
let mut result: Vec<StringRecord> = Vec::new();
// Iterate through records
for record in rdr.records() {
result.push(record?);
}
// Ok!
Ok(result)
}
fn save(&self, records: Vec<StringRecord>) -> Result<()> {
// Writing to the path we want
let mut writer = csv::Writer::from_path(&self.file_out)?;
// Creating the Header
writer.write_record(&["Date", "Description", "Amount"])?;
// Adding all Records
for record in &records {
writer.write_record(record)?;
}
// Flushing!!
writer.flush()?;
// Ok!!
Ok(())
}
pub fn start(&self) -> Result<()> {
// Holding all Records
let mut records: Vec<StringRecord> = Vec::new();
// Using WalkDir to go through the Directory
for entry in WalkDir::new(&self.directory) {
// Reference the Path
let entry = entry?;
let path = entry.path();
// Is it a file?
if !path.is_file() {
continue;
}
// Reading the CSV from the Path
let file = self.read_csv(path.to_str().unwrap())?;
// Adding it to the record list
records.extend(file);
}
// Saving the Records
self.save(records)?;
// Ok!!
Ok(())
}
}

View file

@ -5,5 +5,5 @@ clear
docker run --rm -it \ docker run --rm -it \
-v "$PWD/project:/src:Z" \ -v "$PWD/project:/src:Z" \
-v "$PWD/build:/app:Z" \ -v "$PWD/build:/app:Z" \
-e "PROJ_NAME=statement-converter" \ -e "PROJ_NAME=example" \
rust-buildbot $@ rust-buildbot $@