generated from OBJNULL/Dockerized-Rust
Compare commits
10 commits
Author | SHA1 | Date | |
---|---|---|---|
4d467774d1 | |||
8483733678 | |||
c2f6dd47b4 | |||
820b024d10 | |||
bfa80e061c | |||
d293452929 | |||
803e59e21f | |||
2555c31e92 | |||
977c9b5ce3 | |||
cb4d151960 |
5 changed files with 210 additions and 26 deletions
|
@ -1,10 +1,11 @@
|
||||||
[package]
|
[package]
|
||||||
name = "example"
|
name = "statement-converter"
|
||||||
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"
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
// 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
|
||||||
|
@ -15,36 +24,98 @@ 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)
|
||||||
/*
|
/*
|
||||||
PDF Path
|
-- Convert Mode
|
||||||
*/
|
*/
|
||||||
.arg(
|
.subcommand(
|
||||||
Arg::new("file_in")
|
Command::new("convert")
|
||||||
.short('i')
|
.short_flag('c')
|
||||||
.long("file_in")
|
.long_flag("convert")
|
||||||
.help("The PDF you want to convert")
|
.about("Converts PDF Statements to CSV Files")
|
||||||
.action(ArgAction::Set)
|
.arg(
|
||||||
.required(true),
|
Arg::new("file_in")
|
||||||
|
.id("file_in")
|
||||||
|
.help("The PDF you want to convert")
|
||||||
|
.action(ArgAction::Set)
|
||||||
|
.required(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("file_out")
|
||||||
|
.id("file_out")
|
||||||
|
.help("The CSV Path you want to save to")
|
||||||
|
.action(ArgAction::Set)
|
||||||
|
.required(true),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.subcommand(
|
||||||
Arg::new("file_out")
|
Command::new("package")
|
||||||
.short('o')
|
.short_flag('p')
|
||||||
.long("file_out")
|
.long_flag("package")
|
||||||
.help("The CSV Path you want to save to")
|
.about("Combines all CSV Files in a given directory into one MASSIVE one")
|
||||||
.action(ArgAction::Set)
|
.arg(
|
||||||
.required(true),
|
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 the required arguments
|
// Getting required arguments
|
||||||
let file_input = matches.get_one::<String>("file_in").unwrap().to_string();
|
let mode: ArgModes;
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,22 @@
|
||||||
// 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;
|
||||||
|
|
||||||
// Entry-Point
|
// Functions
|
||||||
fn main() -> Result<()> {
|
fn convert(args: &Arguments) -> Result<()> {
|
||||||
// Reading the Arguments
|
|
||||||
let args = Arguments::new();
|
|
||||||
|
|
||||||
// Display Status
|
// Display Status
|
||||||
printer::print_generic("📃", "Extracting Text");
|
printer::print_generic("📃", "Extracting Text");
|
||||||
|
|
||||||
|
@ -43,6 +42,31 @@ fn main() -> 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(())
|
||||||
}
|
}
|
||||||
|
|
88
project/src/packager.rs
Normal file
88
project/src/packager.rs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
// 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(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -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=example" \
|
-e "PROJ_NAME=statement-converter" \
|
||||||
rust-buildbot $@
|
rust-buildbot $@
|
||||||
|
|
Loading…
Reference in a new issue