You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
4.7 KiB
123 lines
4.7 KiB
use chrono::NaiveDateTime;
|
|
use tiberius::{Client, Config, Query, AuthMethod, Row};
|
|
use tokio::net::TcpStream;
|
|
use tokio_util::compat::{TokioAsyncWriteCompatExt, Compat};
|
|
mod pymt_trans_table;
|
|
use pymt_trans_table::{PaymentData, FromSqlRow};
|
|
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder, dev::Payload};
|
|
use serde::{Serialize, Deserialize};
|
|
use dotenv::dotenv;
|
|
use std::env::var;
|
|
|
|
|
|
type BDynError = Box< dyn std::error::Error>;
|
|
|
|
#[actix_web::main]
|
|
async fn main() -> Result<(), BDynError> {
|
|
HttpServer::new(|| {
|
|
App::new()
|
|
.service(search_contract)
|
|
})
|
|
.bind(("127.0.0.1", 8080))?
|
|
.run()
|
|
.await;
|
|
Ok(())
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct ContractNumber {
|
|
contract_number: String
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct SearchResponse {
|
|
pub paid_in_full : Vec<PaymentData>,
|
|
pub checks: Option<Vec<[String;2]>>
|
|
}
|
|
|
|
#[get("/contract/{contract_number}")]
|
|
async fn search_contract(contract_number: web::Path<String>) -> HttpResponse {
|
|
let mut resp = SearchResponse{paid_in_full: vec![], checks: None};
|
|
dotenv().ok();
|
|
let mut config = Config::new();
|
|
config.host(var("HOST").expect("No HOST set in .env"));
|
|
config.port(var("PORT").expect("No HOST set in .env").parse::<u16>().expect("Could not parse port to u16"));
|
|
config.authentication(AuthMethod::windows(var("USER_NAME").expect("No USER_NAME set in .env"), var("PASSWORD").expect("No PASSWORD set in .env")));
|
|
config.trust_cert(); // on production, it is not a good idea to do this
|
|
|
|
let paid_in_full = get_paid_in_full(config.clone(), contract_number.to_string()).await;
|
|
let mut checks = vec![];
|
|
match paid_in_full {
|
|
Ok(pif) => {
|
|
if pif.len() > 0 {
|
|
for payment in pif {
|
|
if payment.is_check() {
|
|
checks.push(payment.check_info());
|
|
}
|
|
resp.paid_in_full.push(payment);
|
|
}
|
|
let found_checks = find_checks(config, checks).await;
|
|
match found_checks {
|
|
Ok(check_list) => {resp.checks = Some(check_list);},
|
|
Err(e) => {return HttpResponse::NotFound().body("Contract not found")}
|
|
}
|
|
};
|
|
},
|
|
Err(e) => {return HttpResponse::NotFound().body("Contract not found")}
|
|
}
|
|
HttpResponse::Ok().body(serde_json::json!(resp).to_string())
|
|
}
|
|
|
|
async fn create_sql_conn(config: Config) -> Result<Client<Compat<TcpStream>>, BDynError> {
|
|
let tcp = TcpStream::connect(config.get_addr()).await?;
|
|
tcp.set_nodelay(true)?;
|
|
|
|
Ok(Client::connect(config, tcp.compat_write()).await?)
|
|
}
|
|
|
|
fn create_table_struct<T>(sql_result: Vec<Row>) -> Result<Vec<T>, BDynError>
|
|
where T: FromSqlRow<T>
|
|
{
|
|
let mut table: Vec<T> = vec![];
|
|
for row in sql_result {
|
|
let raw_data = T::from_sql_row(row);
|
|
match raw_data {
|
|
Ok(structure_data) => table.push(structure_data),
|
|
Err(e) => {}
|
|
}
|
|
}
|
|
Ok(table)
|
|
}
|
|
|
|
async fn get_paid_in_full(config: Config, contract_number: String) -> Result<Vec<PaymentData>, BDynError> {
|
|
let mut client = create_sql_conn(config).await?;
|
|
let pif_query = Query::new(format!("USE NLCF SELECT TRXDSCRN as ContractNumber, BACHNUMB, VENDORID, PRCHAMNT, DOCDATE, DEX_ROW_TS FROM PM30200 WHERE TRXDSCRN = '{}'", contract_number));
|
|
let stream = pif_query.query(&mut client).await?;
|
|
let row = stream.into_first_result().await?;
|
|
create_table_struct(row)
|
|
}
|
|
|
|
async fn find_checks(config: Config, search_data: Vec<(String, String, NaiveDateTime)>) -> Result<Vec<[String;2]>, BDynError>{
|
|
use walkdir::{WalkDir, DirEntry};
|
|
let mut client = create_sql_conn(config).await?;
|
|
let mut found_checks: Vec<[String;2]> = vec![];
|
|
|
|
for (vendor_id, bach_num, timestamp) in search_data {
|
|
let check_query = Query::new(format!("USE NLCF SELECT VENDORID, CHEKNUMB, CHEKAMNT FROM ME240461
|
|
WHERE VENDORID = '{}' AND BACHNUMB= '{}' AND DOCDATE >= {}", vendor_id, bach_num, timestamp.format("%Y-%m-%d")));
|
|
let stream = check_query.query(&mut client).await?;
|
|
let rows = stream.into_first_result().await?;
|
|
if rows.len() < 1 {continue}
|
|
for row in rows {
|
|
let check_number: &str = row.get("CHEKNUMB").unwrap();
|
|
let vendor: &str = row.get("VENDORID").unwrap();
|
|
let files: Vec<DirEntry> = WalkDir::new(&format!("{}*{}*",
|
|
var("CHECK_FOLDER").expect("No HOST set in .env") ,check_number))
|
|
.into_iter().filter_map(|e| e.ok())
|
|
.collect();
|
|
if files.len() > 0 {found_checks.push([vendor.to_string(), files[0].file_name().to_str().unwrap().to_string()])}
|
|
}
|
|
}
|
|
Ok(found_checks)
|
|
}
|
|
|
|
|