diff --git a/Cargo.lock b/Cargo.lock index 66087c20..9c69dc36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,6 +74,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + [[package]] name = "array-init" version = "2.1.0" @@ -1490,6 +1496,12 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + [[package]] name = "either" version = "1.9.0" @@ -1646,6 +1658,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -2607,6 +2625,33 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mockall" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "multer" version = "3.0.0" @@ -2898,6 +2943,7 @@ dependencies = [ "chrono", "dotenvy", "geo-types", + "mockall", "regex", "rust_decimal", "serde", @@ -3092,6 +3138,32 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "predicates" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +dependencies = [ + "anstyle", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -3931,8 +4003,10 @@ version = "0.1.0" dependencies = [ "cognitoidp", "httpclient", + "mockall", "pg", "rust_decimal", + "tokio", "types", ] @@ -4248,6 +4322,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + [[package]] name = "tests" version = "0.1.0" diff --git a/README.md b/README.md index d25bc325..82350e32 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ encryption and replication are secondary government is not above failure, nor is it entitled to steal from the private sector to conceal its failure. improving government depends on failure [predicting](https://en.wikipedia.org/wiki/Time_travel_debugging) the individuals and laws that must be replaced. flying a flag and demanding loyalty before this step is just misdirection **q.** how does systemaccounting manage expectation? -**a.** central banks providing "forward guidance" appease more than they set expectation when they allow interest rate manipulation and money printing. systemaccounting prices capital by switching the "risk-free" rate from referencing the hackable price of debt to the immutably recorded price of equity. when the risk-free rate refers to the empirical rate, i.e. to the historical and not the expected, the economy remains protected from the catastrophic failure indulged by intended government mispricing +**a.** central banks providing "forward guidance" appease more than they set expectation when they allow interest rate manipulation and money printing. systemaccounting prices capital by switching the "risk-free" rate from referencing the hackable price of debt to the immutably recorded price of equity. when the risk-free rate refers to the empirical rate, i.e. to the historical and not the expected, the economy remains protected from the catastrophic failure indulged by government mispricing removing financial appeasement guides the freedom of speech by recalibrating expectation to the empirical diff --git a/crates/pg/Cargo.toml b/crates/pg/Cargo.toml index 442415f9..9450901d 100644 --- a/crates/pg/Cargo.toml +++ b/crates/pg/Cargo.toml @@ -17,6 +17,7 @@ serde-aux = { version = "4.4.0", default-features = false } rust_decimal = { version = "1.34.3", features = ["db-tokio-postgres"] } geo-types = "=0.7.0" chrono = "0.4.23" +mockall = "0.12.1" [dev-dependencies] dotenvy = "0.15.7" diff --git a/crates/pg/src/model.rs b/crates/pg/src/model.rs index e3a8dbc6..19e95243 100644 --- a/crates/pg/src/model.rs +++ b/crates/pg/src/model.rs @@ -3,6 +3,7 @@ use crate::postgres::{DatabaseConnection, ToSqlVec}; use crate::sqls::common::TableTrait; use chrono::{DateTime, Utc}; use geo_types::Point; +use mockall::automock; use rust_decimal::Decimal; use std::{error::Error, vec}; use types::{ @@ -20,6 +21,7 @@ const FIXED_DECIMAL_PLACES: usize = 3; // todo: add future boilerplate // https://doc.rust-lang.org/beta/rustc/lints/listing/warn-by-default.html#async-fn-in-trait +#[automock] pub trait ModelTrait { async fn insert_account_query(&self, account: String) -> Result<(), Box>; async fn delete_owner_account_query(&self, account: String) -> Result<(), Box>; diff --git a/crates/service/Cargo.toml b/crates/service/Cargo.toml index fa4c43f3..ab832c32 100644 --- a/crates/service/Cargo.toml +++ b/crates/service/Cargo.toml @@ -10,3 +10,7 @@ rust_decimal = { version = "1.34.3", default-features = false } httpclient = { path = "../httpclient" } pg = { path = "../pg" } cognitoidp = { path = "../cognitoidp" } + +[dev-dependencies] +mockall = "0.12.1" +tokio = { version = "1.35.1", default-features = false, features = ["macros"] } diff --git a/crates/service/src/lib.rs b/crates/service/src/lib.rs index ee178d32..eababb5d 100644 --- a/crates/service/src/lib.rs +++ b/crates/service/src/lib.rs @@ -14,12 +14,12 @@ use types::{ transaction_item::TransactionItems, }; -pub struct Service { - conn: T, +pub struct Service<'a, T: ModelTrait> { + conn: &'a T, } -impl Service { - pub fn new(conn: T) -> Self { +impl<'a, T: ModelTrait> Service<'a, T> { + pub fn new(conn: &'a T) -> Self { Self { conn } } @@ -214,7 +214,7 @@ impl Service { request .clone() .transaction_items - .test_unique_contra_accounts()?; + .test_unique_contra_accounts()?; // cadet todo: add unit test let mut approval_time: Option = None; @@ -254,7 +254,6 @@ impl Service { self.change_account_balances(post_approval_transaction.transaction_items.clone()) .await?; } - // todo: notify role approvers in transaction // create intra transaction @@ -319,13 +318,6 @@ impl Service { Ok(transaction) } - pub async fn create_transaction_tx( - &mut self, - transaction: Transaction, - ) -> Result> { - self.conn.insert_transaction_tx_query(transaction).await - } - pub async fn get_last_n_requests( &self, account: String, @@ -501,3 +493,1505 @@ impl Service { .await } } + +// duplicates Service to support mutable +// reference required by transaction query +pub struct TxService<'a, T: ModelTrait> { + conn: &'a mut T, +} + +impl<'a, T: ModelTrait> TxService<'a, T> { + pub fn new(conn: &'a mut T) -> Self { + Self { conn } + } + + pub async fn create_transaction_tx( + &mut self, + transaction: Transaction, + ) -> Result> { + self.conn.insert_transaction_tx_query(transaction).await + } + + pub async fn get_profile_ids_by_account_names( + &self, + account_names: Vec, + ) -> Result> { + match self + .conn + .select_profile_ids_by_account_names_query(account_names) + .await + { + Ok(profile_ids) => { + let map = ProfileIds::from(profile_ids); + Ok(map) + } + Err(e) => Err(e), + } + } + + pub async fn get_full_transaction_by_id( + &self, + transaction_id: i32, + ) -> Result> { + let transaction = self + .get_transaction_with_transaction_items_and_approvals_by_id(transaction_id) + .await?; + Ok(transaction) + } + + async fn get_transaction_with_transaction_items_and_approvals_by_id( + &self, + transaction_id: i32, + ) -> Result> { + let mut transaction = self + .conn + .select_transaction_by_id_query(transaction_id) + .await?; + + let transaction_items = self + .get_transaction_items_by_transaction_id(transaction_id) + .await?; + + let approvals = self.get_approvals_by_transaction_id(transaction_id).await?; + + transaction.build(transaction_items, approvals)?; + Ok(transaction) + } + + pub async fn get_transaction_items_by_transaction_id( + &self, + transaction_id: i32, + ) -> Result> { + self.conn + .select_transaction_items_by_transaction_id_query(transaction_id) + .await + } + + pub async fn get_approvals_by_transaction_id( + &self, + transaction_id: i32, + ) -> Result> { + self.conn + .select_approvals_by_transaction_id_query(transaction_id) + .await + } +} + +#[cfg(test)] +mod tests { + use std::{str::FromStr, vec}; + + use mockall::predicate; + use pg::model::MockModelTrait; + use rust_decimal::Decimal; + use types::{ + account::{AccountProfile, AccountProfiles}, + account_role::AccountRole, + approval::{Approval, Approvals}, + balance::{AccountBalance, AccountBalances}, + rule::{RuleInstance, RuleInstances}, + time::TZTime, + transaction::{Transaction, Transactions}, + transaction_item::{TransactionItem, TransactionItems}, + }; + + #[tokio::test] + async fn create_account_queries_by_account() { + let mut conn = MockModelTrait::new(); + let account = "test_account".to_string(); + + conn.expect_insert_account_query() + .with(predicate::eq(account.clone())) + .times(1) + .returning(|_| Ok(())); + + let service = super::Service::new(&conn); + + let _ = service.create_account(account).await; + } + + #[tokio::test] + async fn delete_owner_account_queries_by_account() { + let mut conn = MockModelTrait::new(); + let account = "test_account".to_string(); + + conn.expect_delete_owner_account_query() + .with(predicate::eq(account.clone())) + .times(1) + .returning(|_| Ok(())); + + let service = super::Service::new(&conn); + + let _ = service.delete_owner_account(account).await; + } + + #[tokio::test] + async fn create_account_profile_queries_by_account_profile() { + let mut conn = MockModelTrait::new(); + let test_account_profile = create_test_account_profiles().0[0].clone(); + + conn.expect_insert_account_profile_query() + .with(predicate::eq(test_account_profile.clone())) + .times(1) + .returning(|_| Ok("test_account".to_string())); + + let service = super::Service::new(&conn); + + let _ = service.create_account_profile(test_account_profile).await; + } + + #[tokio::test] + async fn get_profile_ids_by_account_names_queries_by_account_names() { + let mut conn = MockModelTrait::new(); + let account_names = vec!["test_account".to_string()]; + + conn.expect_select_profile_ids_by_account_names_query() + .with(predicate::eq(account_names.clone())) + .times(1) + .returning(|_| Ok(vec![])); + + let service = super::Service::new(&conn); + + let _ = service + .get_profile_ids_by_account_names(account_names) + .await; + } + + #[tokio::test] + async fn create_account_balance_queries_by_account_balance() { + let mut conn = MockModelTrait::new(); + let account = "test_account".to_string(); + let balance = 100.into(); + let curr_tr_item_id = 1; + + conn.expect_insert_account_balance_query() + .with( + predicate::eq(account.clone()), + predicate::eq(balance), + predicate::eq(curr_tr_item_id), + ) + .times(1) + .returning(|_, _, _| Ok(())); + + let service = super::Service::new(&conn); + + let _ = service + .create_account_balance(account, balance, curr_tr_item_id) + .await; + } + + #[tokio::test] + async fn get_account_balance_queries_by_account() { + let mut conn = MockModelTrait::new(); + let account = "test_account".to_string(); + + conn.expect_select_account_balance_query() + .with(predicate::eq(account.clone())) + .times(1) + .returning(|_| Ok("100".to_string())); + + let service = super::Service::new(&conn); + + let _ = service.get_account_balance(account).await; + } + + #[tokio::test] + async fn get_account_balances_queries_by_accounts() { + let mut conn = MockModelTrait::new(); + let accounts = vec!["test_account".to_string()]; + + conn.expect_select_account_balances_query() + .with(predicate::eq(accounts.clone())) + .times(1) + .returning(|_| Ok(AccountBalances::new())); + + let service = super::Service::new(&conn); + + let _ = service.get_account_balances(accounts).await; + } + + #[tokio::test] + async fn get_debitor_account_balances_queries_by_transaction_items() { + let mut conn = MockModelTrait::new(); + let test_transaction_items = create_test_transaction_items(); + + conn.expect_select_account_balances_query() + .times(1) + .returning(|_| Ok(AccountBalances::new())); + + let service = super::Service::new(&conn); + + let _ = service + .get_debitor_account_balances(test_transaction_items) + .await; + } + + #[tokio::test] + async fn change_account_balances_queries_by_transaction_items() { + let mut conn = MockModelTrait::new(); + let test_transaction_items = create_test_transaction_items(); + + conn.expect_update_account_balances_query() + .with(predicate::eq(test_transaction_items.clone())) + .times(1) + .returning(|_| Ok(())); + + let service = super::Service::new(&conn); + + let _ = service + .change_account_balances(test_transaction_items) + .await; + } + + #[tokio::test] + async fn test_sufficient_debitor_funds_queries_by_transaction_items() { + let mut conn = MockModelTrait::new(); + let test_transaction_items = create_test_transaction_items(); + + conn.expect_select_account_balances_query() + .times(1) + .returning(|_| { + let mut test_account_balances = AccountBalances::new(); + test_account_balances.push(AccountBalance { + account_name: "JacobWebb".to_string(), + current_balance: Decimal::from_str("1000.000").unwrap(), + current_transaction_item_id: Some("1".to_string()), + }); + Ok(test_account_balances) + }); + + let service = super::Service::new(&conn); + + let _ = service + .test_sufficient_debitor_funds(test_transaction_items) + .await; + } + + #[tokio::test] + async fn test_sufficient_debitor_funds_errors_when_insufficient_funds() { + let mut conn = MockModelTrait::new(); + let test_transaction_items = create_test_transaction_items(); + + conn.expect_select_account_balances_query() + .times(1) + .returning(|_| { + let mut test_account_balances = AccountBalances::new(); + test_account_balances.push(AccountBalance { + account_name: "JacobWebb".to_string(), + current_balance: Decimal::from_str("0.000").unwrap(), + current_transaction_item_id: Some("1".to_string()), + }); + Ok(test_account_balances) + }); + + let service = super::Service::new(&conn); + + let result = service + .test_sufficient_debitor_funds(test_transaction_items) + .await; + + assert!(result.is_err()); + } + + #[tokio::test] + async fn add_approval_times_by_account_and_role_queries_by_transaction_id_account_and_role() { + let mut conn = MockModelTrait::new(); + let transaction_id = 1; + let account = "test_account".to_string(); + let role = AccountRole::Debitor; + + conn.expect_update_approvals_by_account_and_role_query() + .with( + predicate::eq(transaction_id), + predicate::eq(account.clone()), + predicate::eq(role), + ) + .times(1) + .returning(|_, _, _| Ok(None)); + + let service = super::Service::new(&conn); + + let _ = service + .add_approval_times_by_account_and_role(transaction_id, account, role) + .await; + } + + #[tokio::test] + async fn get_transaction_with_transaction_items_and_approvals_by_id_queries_by_transaction_id() + { + let mut conn = MockModelTrait::new(); + let transaction_id = 1; + + conn.expect_select_transaction_by_id_query() + .with(predicate::eq(transaction_id)) + .times(1) + .returning(|_| Ok(create_test_transaction())); + + conn.expect_select_transaction_items_by_transaction_id_query() + .with(predicate::eq(transaction_id)) + .times(1) + .returning(|_| Ok(create_test_transaction_items())); + + conn.expect_select_approvals_by_transaction_id_query() + .with(predicate::eq(transaction_id)) + .times(1) + .returning(|_| { + Ok(create_test_transaction_items().0[0] + .approvals + .as_ref() + .unwrap() + .clone()) + }); + + let service = super::Service::new(&conn); + + let _ = service + .get_transaction_with_transaction_items_and_approvals_by_id(transaction_id) + .await; + } + + #[tokio::test] + async fn get_transactions_with_transaction_items_and_approvals_by_ids_queries_by_transaction_ids( + ) { + let mut conn = MockModelTrait::new(); + let transaction_ids = vec![1, 2]; + + conn.expect_select_transactions_by_ids_query() + .with(predicate::eq(transaction_ids.clone())) + .times(1) + .returning(|_| { + let mut test_transactions = + Transactions(vec![create_test_transaction(), create_test_transaction()]); + for tr in test_transactions.0.iter_mut() { + tr.transaction_items = TransactionItems(vec![]); + } + Ok(test_transactions) + }); + + conn.expect_select_transaction_items_by_transaction_ids_query() + .with(predicate::eq(transaction_ids.clone())) + .times(1) + .returning(|_| { + let mut test_transaction_items = create_test_transaction_items(); + for tr_item in test_transaction_items.0.iter_mut() { + tr_item.approvals = None; + } + Ok(test_transaction_items) + }); + + conn.expect_select_approvals_by_transaction_ids_query() + .with(predicate::eq(transaction_ids.clone())) + .times(1) + .returning(|_| { + Ok(create_test_transaction_items().0[0] + .approvals + .as_ref() + .unwrap() + .clone()) + }); + + let service = super::Service::new(&conn); + + let _ = service + .get_transactions_with_transaction_items_and_approvals_by_ids(transaction_ids) + .await; + } + + #[tokio::test] + async fn approve_called_with_args() { + let mut conn = MockModelTrait::new(); + let test_auth_account = "JacobWebb".to_string(); + let test_approver_role = AccountRole::Debitor; + let test_request = create_test_transaction(); + let test_transaction_id = 1; + + conn.expect_select_account_balances_query() + .times(1) + .with(predicate::eq(vec![test_auth_account.clone()])) + .returning(|_| { + let mut test_account_balances = AccountBalances::new(); + test_account_balances.push(AccountBalance { + account_name: "JacobWebb".to_string(), + current_balance: Decimal::from_str("1000.000").unwrap(), + current_transaction_item_id: Some("1".to_string()), + }); + Ok(test_account_balances) + }); + + conn.expect_update_approvals_by_account_and_role_query() + .with( + predicate::eq(test_transaction_id), + predicate::eq(test_auth_account.clone()), + predicate::eq(test_approver_role), + ) + .times(1) + .returning(|_, _, _| Ok(None)); + + conn.expect_select_transaction_by_id_query() + .times(1) + .with(predicate::eq(test_transaction_id)) + .returning(|_| { + let mut test_transaction = create_test_transaction(); + test_transaction.equilibrium_time = Some(TZTime::now()); + test_transaction.transaction_items = TransactionItems(vec![]); + Ok(test_transaction) + }); + + conn.expect_select_transaction_items_by_transaction_id_query() + .times(1) + .with(predicate::eq(test_transaction_id)) + .returning(|_| { + let mut test_transaction_items = create_test_transaction_items(); + for tr_item in test_transaction_items.0.iter_mut() { + tr_item.approvals = None; + } + Ok(test_transaction_items) + }); + + conn.expect_select_approvals_by_transaction_id_query() + .times(1) + .with(predicate::eq(test_transaction_id)) + .returning(|_| { + let mut test_approvals = Approvals(vec![]); + for tr_item in create_test_transaction_items().0.iter() { + for approval in tr_item.approvals.as_ref().unwrap().0.iter() { + test_approvals.0.push(approval.clone()); + } + } + Ok(test_approvals) + }); + + conn.expect_update_account_balances_query() + .with(predicate::eq(create_test_transaction_items())) + .times(1) + .returning(|_| Ok(())); + + let service = super::Service::new(&conn); + + let _ = service + .approve(test_auth_account, test_approver_role, test_request) + .await + .unwrap(); + } + + #[tokio::test] + async fn add_approve_all_credit_rule_instance_if_not_exists_queries_by_account_name() { + let mut conn = MockModelTrait::new(); + let account_name = "JacobWebb".to_string(); + + conn.expect_select_approve_all_credit_rule_instance_exists_query() + .with(predicate::eq(account_name.clone())) + .times(1) + .returning(|_| Ok(false)); + + conn.expect_insert_approve_all_credit_rule_instance_query() + .with(predicate::eq(account_name.clone())) + .times(1) + .returning(|_| Ok(())); + + let service = super::Service::new(&conn); + + let _ = service + .add_approve_all_credit_rule_instance_if_not_exists(account_name) + .await; + } + + #[tokio::test] + async fn create_account_from_cognito_trigger_queries_by_account_profile() { + let mut conn = MockModelTrait::new(); + let test_account_profile = create_test_account_profiles().0[0].clone(); + let beginning_balance = Decimal::from_str("1000.000").unwrap(); + let current_transaction_item_id = 1; + + conn.expect_insert_account_query() + .with(predicate::eq(test_account_profile.account_name.clone())) + .times(1) + .returning(|_| Ok(())); + + conn.expect_insert_account_profile_query() + .with(predicate::eq(test_account_profile.clone())) + .times(1) + .returning(|_| Ok("test_account".to_string())); + + conn.expect_insert_account_balance_query() + .with( + predicate::eq(test_account_profile.account_name.clone()), + predicate::eq(beginning_balance), + predicate::eq(current_transaction_item_id), + ) + .times(1) + .returning(|_, _, _| Ok(())); + + conn.expect_insert_approve_all_credit_rule_instance_query() + .with(predicate::eq(test_account_profile.account_name.clone())) + .times(1) + .returning(|_| Ok(())); + + conn.expect_select_approve_all_credit_rule_instance_exists_query() + .with(predicate::eq(test_account_profile.account_name.clone())) + .times(1) + .returning(|_| Ok(false)); + + let service = super::Service::new(&conn); + + let _ = service + .create_account_from_cognito_trigger( + test_account_profile, + beginning_balance, + current_transaction_item_id, + ) + .await; + } + + #[tokio::test] + async fn get_transaction_by_id_queries_by_transaction_id() { + let mut conn = MockModelTrait::new(); + let transaction_id = 1; + + conn.expect_select_transaction_by_id_query() + .with(predicate::eq(transaction_id)) + .times(1) + .returning(|_| Ok(create_test_transaction())); + + let service = super::Service::new(&conn); + + let _ = service.get_transaction_by_id(transaction_id).await; + } + + #[tokio::test] + async fn get_full_transaction_by_id_queries_by_transaction_id() { + let mut conn = MockModelTrait::new(); + let transaction_id = 1; + + conn.expect_select_transaction_by_id_query() + .with(predicate::eq(transaction_id)) + .times(1) + .returning(|_| Ok(create_test_transaction())); + + conn.expect_select_transaction_items_by_transaction_id_query() + .with(predicate::eq(transaction_id)) + .times(1) + .returning(|_| Ok(create_test_transaction_items())); + + conn.expect_select_approvals_by_transaction_id_query() + .with(predicate::eq(transaction_id)) + .times(1) + .returning(|_| { + Ok(create_test_transaction_items().0[0] + .approvals + .as_ref() + .unwrap() + .clone()) + }); + + let service = super::Service::new(&conn); + + let _ = service.get_full_transaction_by_id(transaction_id).await; + } + + #[tokio::test] + async fn get_last_n_requests_queries_by_account_and_n() { + let mut conn = MockModelTrait::new(); + let account = "JacobWebb".to_string(); + let n = 10; + + conn.expect_select_last_n_requests_query() + .with(predicate::eq(account.clone()), predicate::eq(n)) + .times(1) + .returning(|_, _| Ok(create_test_transactions())); + + conn.expect_select_transaction_items_by_transaction_ids_query() + .with(predicate::eq( + create_test_transactions().list_ids().unwrap(), + )) + .times(1) + .returning(|_| Ok(create_test_transaction_items())); + + conn.expect_select_approvals_by_transaction_ids_query() + .with(predicate::eq( + create_test_transactions().list_ids().unwrap(), + )) + .times(1) + .returning(|_| { + Ok(create_test_transaction_items().0[0] + .approvals + .as_ref() + .unwrap() + .clone()) + }); + + let service = super::Service::new(&conn); + + let _ = service.get_last_n_requests(account, n).await; + } + + #[tokio::test] + async fn get_last_n_transactions_queries_by_account_and_n() { + let mut conn = MockModelTrait::new(); + let account = "JacobWebb".to_string(); + let n = 10; + + conn.expect_select_last_n_transactions_query() + .with(predicate::eq(account.clone()), predicate::eq(n)) + .times(1) + .returning(|_, _| Ok(create_test_transactions())); + + conn.expect_select_transaction_items_by_transaction_ids_query() + .with(predicate::eq( + create_test_transactions().list_ids().unwrap(), + )) + .times(1) + .returning(|_| Ok(create_test_transaction_items())); + + conn.expect_select_approvals_by_transaction_ids_query() + .with(predicate::eq( + create_test_transactions().list_ids().unwrap(), + )) + .times(1) + .returning(|_| { + Ok(create_test_transaction_items().0[0] + .approvals + .as_ref() + .unwrap() + .clone()) + }); + + let service = super::Service::new(&conn); + + let _ = service.get_last_n_transactions(account, n).await; + } + + #[tokio::test] + async fn get_transaction_items_and_approvals_by_transaction_ids_queries_by_transaction_ids() { + let mut conn = MockModelTrait::new(); + let transaction_ids = vec![1, 2]; + + conn.expect_select_transaction_items_by_transaction_ids_query() + .with(predicate::eq(transaction_ids.clone())) + .times(1) + .returning(|_| Ok(create_test_transaction_items())); + + conn.expect_select_approvals_by_transaction_ids_query() + .with(predicate::eq(transaction_ids.clone())) + .times(1) + .returning(|_| { + Ok(create_test_transaction_items().0[0] + .approvals + .as_ref() + .unwrap() + .clone()) + }); + + let service = super::Service::new(&conn); + + let _ = service + .get_transaction_items_and_approvals_by_transaction_ids(transaction_ids) + .await; + } + + #[tokio::test] + async fn get_transaction_items_by_transaction_id_queries_by_transaction_id() { + let mut conn = MockModelTrait::new(); + let transaction_id = 1; + + conn.expect_select_transaction_items_by_transaction_id_query() + .with(predicate::eq(transaction_id)) + .times(1) + .returning(|_| Ok(create_test_transaction_items())); + + let service = super::Service::new(&conn); + + let _ = service + .get_transaction_items_by_transaction_id(transaction_id) + .await; + } + + #[tokio::test] + async fn get_transaction_items_by_transaction_ids_queries_by_transaction_ids() { + let mut conn = MockModelTrait::new(); + let transaction_ids = vec![1, 2]; + + conn.expect_select_transaction_items_by_transaction_ids_query() + .with(predicate::eq(transaction_ids.clone())) + .times(1) + .returning(|_| Ok(create_test_transaction_items())); + + let service = super::Service::new(&conn); + + let _ = service + .get_transaction_items_by_transaction_ids(transaction_ids) + .await; + } + + #[tokio::test] + async fn get_approvals_by_transaction_id_queries_by_transaction_id() { + let mut conn = MockModelTrait::new(); + let transaction_id = 1; + + conn.expect_select_approvals_by_transaction_id_query() + .with(predicate::eq(transaction_id)) + .times(1) + .returning(|_| { + Ok(create_test_transaction_items().0[0] + .approvals + .as_ref() + .unwrap() + .clone()) + }); + + let service = super::Service::new(&conn); + + let _ = service + .get_approvals_by_transaction_id(transaction_id) + .await; + } + + #[tokio::test] + async fn get_approvals_by_transaction_ids_queries_by_transaction_ids() { + let mut conn = MockModelTrait::new(); + let transaction_ids = vec![1, 2]; + + conn.expect_select_approvals_by_transaction_ids_query() + .with(predicate::eq(transaction_ids.clone())) + .times(1) + .returning(|_| { + Ok(create_test_transaction_items().0[0] + .approvals + .as_ref() + .unwrap() + .clone()) + }); + + let service = super::Service::new(&conn); + + let _ = service + .get_approvals_by_transaction_ids(transaction_ids) + .await; + } + + #[tokio::test] + async fn get_account_approvers_queries_by_account() { + let mut conn = MockModelTrait::new(); + let account = "JacobWebb".to_string(); + + conn.expect_select_approvers_query() + .with(predicate::eq(account.clone())) + .times(1) + .returning(|_| Ok(vec![])); + + let service = super::Service::new(&conn); + + let _ = service.get_account_approvers(account).await; + } + + #[tokio::test] + async fn get_tr_item_rule_instances_by_role_account_queries_by_account_role_and_account_name() { + let mut conn = MockModelTrait::new(); + let account_role = AccountRole::Debitor; + let account_name = "JacobWebb".to_string(); + + conn.expect_select_rule_instance_by_type_role_account_query() + .with( + predicate::eq("transaction_item".to_string()), + predicate::eq(account_role), + predicate::eq(account_name.clone()), + ) + .times(1) + .returning(|_, _, _| { + Ok(RuleInstances(vec![RuleInstance { + id: Some(String::from("1")), + rule_type: String::from("transaction_item"), + rule_name: String::from("multiplyItemValue"), + rule_instance_name: String::from("NinePercentSalesTax"), + variable_values: vec![ + String::from("ANY"), + String::from("StateOfCalifornia"), + String::from("9% state sales tax"), + String::from("0.09"), + ], + account_role: AccountRole::Creditor, + item_id: None, + price: None, + quantity: None, + unit_of_measurement: None, + units_measured: None, + account_name: None, + first_name: None, + middle_name: None, + last_name: None, + country_name: None, + street_id: None, + street_name: None, + floor_number: None, + unit_id: None, + city_name: None, + county_name: None, + region_name: None, + state_name: Some(String::from("California")), + postal_code: None, + latlng: None, + email_address: None, + telephone_country_code: None, + telephone_area_code: None, + telephone_number: None, + occupation_id: None, + industry_id: None, + disabled_time: None, + removed_time: None, + created_at: Some(TZTime::now()), + }])) + }); + + let service = super::Service::new(&conn); + + let _ = service + .get_tr_item_rule_instances_by_role_account(account_role, account_name) + .await; + } + + #[tokio::test] + async fn get_account_profiles_queries_by_account_names() { + let mut conn = MockModelTrait::new(); + let account_names = vec!["JacobWebb".to_string()]; + + conn.expect_select_account_profiles_by_account_names_query() + .with(predicate::eq(account_names.clone())) + .times(1) + .returning(|_| Ok(create_test_account_profiles())); + + let service = super::Service::new(&conn); + + let _ = service.get_account_profiles(account_names).await; + } + + #[tokio::test] + async fn get_state_tr_item_rule_instances_queries_by_account_role_and_state_name() { + let mut conn = MockModelTrait::new(); + let account_role = AccountRole::Debitor; + let state_name = "California".to_string(); + + conn.expect_select_rule_instance_by_type_role_state_query() + .with( + predicate::eq("transaction_item".to_string()), + predicate::eq(account_role), + predicate::eq(state_name.clone()), + ) + .times(1) + .returning(|_, _, _| { + Ok(RuleInstances(vec![RuleInstance { + id: Some(String::from("1")), + rule_type: String::from("transaction_item"), + rule_name: String::from("multiplyItemValue"), + rule_instance_name: String::from("NinePercentSalesTax"), + variable_values: vec![ + String::from("ANY"), + String::from("StateOfCalifornia"), + String::from("9% state sales tax"), + String::from("0.09"), + ], + account_role: AccountRole::Creditor, + item_id: None, + price: None, + quantity: None, + unit_of_measurement: None, + units_measured: None, + account_name: None, + first_name: None, + middle_name: None, + last_name: None, + country_name: None, + street_id: None, + street_name: None, + floor_number: None, + unit_id: None, + city_name: None, + county_name: None, + region_name: None, + state_name: Some(String::from("California")), + postal_code: None, + latlng: None, + email_address: None, + telephone_country_code: None, + telephone_area_code: None, + telephone_number: None, + occupation_id: None, + industry_id: None, + disabled_time: None, + removed_time: None, + created_at: Some(TZTime::now()), + }])) + }); + + let service = super::Service::new(&conn); + + let _ = service + .get_state_tr_item_rule_instances(account_role, state_name) + .await; + } + + #[tokio::test] + async fn get_approval_rule_instances_queries_by_account_role_and_approver_account() { + let mut conn = MockModelTrait::new(); + let account_role = AccountRole::Debitor; + let approver_account = "JacobWebb".to_string(); + + conn.expect_select_rule_instance_by_type_role_account_query() + .with( + predicate::eq("approval".to_string()), + predicate::eq(account_role), + predicate::eq(approver_account.clone()), + ) + .times(1) + .returning(|_, _, _| { + Ok(RuleInstances(vec![RuleInstance { + id: Some(String::from("1")), + rule_type: String::from("approval"), + rule_name: String::from("approveAllCredit"), + rule_instance_name: String::from("ApproveAllCredit"), + variable_values: vec![], + account_role: AccountRole::Debitor, + item_id: None, + price: None, + quantity: None, + unit_of_measurement: None, + units_measured: None, + account_name: None, + first_name: None, + middle_name: None, + last_name: None, + country_name: None, + street_id: None, + street_name: None, + floor_number: None, + unit_id: None, + city_name: None, + county_name: None, + region_name: None, + state_name: None, + postal_code: None, + latlng: None, + email_address: None, + telephone_country_code: None, + telephone_area_code: None, + telephone_number: None, + occupation_id: None, + industry_id: None, + disabled_time: None, + removed_time: None, + created_at: Some(TZTime::now()), + }])) + }); + + let service = super::Service::new(&conn); + + let _ = service + .get_approval_rule_instances(account_role, approver_account) + .await; + } + + pub fn create_test_transactions() -> Transactions { + Transactions(vec![ + Transaction { + id: Some(String::from("1")), + rule_instance_id: None, + author: Some(String::from("GroceryStore")), + author_device_id: None, + author_device_latlng: None, + author_role: Some(AccountRole::Creditor), + equilibrium_time: None, + sum_value: String::from("21.800"), + transaction_items: TransactionItems(vec![ + TransactionItem { + id: Some(String::from("2")), + transaction_id: Some(String::from("1")), + item_id: String::from("bread"), + price: String::from("3.000"), + quantity: String::from("2"), + debitor_first: Some(false), + rule_instance_id: None, + rule_exec_ids: Some(vec![]), + unit_of_measurement: None, + units_measured: None, + debitor: String::from("JacobWebb"), + creditor: String::from("GroceryStore"), + debitor_profile_id: None, + creditor_profile_id: None, + debitor_approval_time: None, + creditor_approval_time: None, + debitor_rejection_time: None, + creditor_rejection_time: None, + debitor_expiration_time: None, + creditor_expiration_time: None, + approvals: Some(Approvals(vec![ + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("1")), + transaction_item_id: Some(String::from("2")), + account_name: String::from("JacobWebb"), + account_role: AccountRole::Debitor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("1")), + transaction_item_id: Some(String::from("2")), + account_name: String::from("GroceryStore"), + account_role: AccountRole::Creditor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + ])), + }, + TransactionItem { + id: Some(String::from("3")), + transaction_id: Some(String::from("1")), + item_id: String::from("milk"), + price: String::from("4.000"), + quantity: String::from("3"), + debitor_first: Some(false), + rule_instance_id: None, + rule_exec_ids: Some(vec![]), + unit_of_measurement: None, + units_measured: None, + debitor: String::from("JacobWebb"), + creditor: String::from("GroceryStore"), + debitor_profile_id: None, + creditor_profile_id: None, + debitor_approval_time: None, + creditor_approval_time: None, + debitor_rejection_time: None, + creditor_rejection_time: None, + debitor_expiration_time: None, + creditor_expiration_time: None, + approvals: Some(Approvals(vec![ + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("1")), + transaction_item_id: Some(String::from("3")), + account_name: String::from("JacobWebb"), + account_role: AccountRole::Debitor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("1")), + transaction_item_id: Some(String::from("3")), + account_name: String::from("GroceryStore"), + account_role: AccountRole::Creditor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + ])), + }, + ]), + }, + Transaction { + id: Some(String::from("2")), + rule_instance_id: None, + author: Some(String::from("GroceryStore")), + author_device_id: None, + author_device_latlng: None, + author_role: Some(AccountRole::Creditor), + equilibrium_time: None, + sum_value: String::from("21.800"), + transaction_items: TransactionItems(vec![ + TransactionItem { + id: Some(String::from("4")), + transaction_id: Some(String::from("2")), + item_id: String::from("bread"), + price: String::from("3.000"), + quantity: String::from("2"), + debitor_first: Some(false), + rule_instance_id: None, + rule_exec_ids: Some(vec![]), + unit_of_measurement: None, + units_measured: None, + debitor: String::from("JacobWebb"), + creditor: String::from("GroceryStore"), + debitor_profile_id: None, + creditor_profile_id: None, + debitor_approval_time: None, + creditor_approval_time: None, + debitor_rejection_time: None, + creditor_rejection_time: None, + debitor_expiration_time: None, + creditor_expiration_time: None, + approvals: Some(Approvals(vec![ + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("2")), + transaction_item_id: Some(String::from("4")), + account_name: String::from("JacobWebb"), + account_role: AccountRole::Debitor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("2")), + transaction_item_id: Some(String::from("4")), + account_name: String::from("GroceryStore"), + account_role: AccountRole::Creditor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + ])), + }, + TransactionItem { + id: Some(String::from("5")), + transaction_id: Some(String::from("2")), + item_id: String::from("milk"), + price: String::from("4.000"), + quantity: String::from("3"), + debitor_first: Some(false), + rule_instance_id: None, + rule_exec_ids: Some(vec![]), + unit_of_measurement: None, + units_measured: None, + debitor: String::from("JacobWebb"), + creditor: String::from("GroceryStore"), + debitor_profile_id: None, + creditor_profile_id: None, + debitor_approval_time: None, + creditor_approval_time: None, + debitor_rejection_time: None, + creditor_rejection_time: None, + debitor_expiration_time: None, + creditor_expiration_time: None, + approvals: Some(Approvals(vec![ + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("2")), + transaction_item_id: Some(String::from("5")), + account_name: String::from("JacobWebb"), + account_role: AccountRole::Debitor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("2")), + transaction_item_id: Some(String::from("5")), + account_name: String::from("GroceryStore"), + account_role: AccountRole::Creditor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + ])), + }, + ]), + }, + ]) + } + + pub fn create_test_account_profiles() -> AccountProfiles { + AccountProfiles(vec![ + AccountProfile { + id: Some(String::from("7")), + account_name: String::from("GroceryStore"), + description: Some(String::from("Sells groceries")), + first_name: Some(String::from("Grocery")), + middle_name: None, + last_name: Some(String::from("Store")), + country_name: String::from("United States of America"), + street_number: Some(String::from("8701")), + street_name: Some(String::from("Lincoln Blvd")), + floor_number: None, + unit_number: None, + city_name: String::from("Los Angeles"), + county_name: Some(String::from("Los Angeles County")), + region_name: None, + state_name: String::from("California"), + postal_code: String::from("90045"), + latlng: Some(String::from("(33.958050,-118.418388)")), + email_address: String::from("grocerystore@address.xz"), + telephone_country_code: Some(String::from("1")), + telephone_area_code: Some(String::from("310")), + telephone_number: Some(String::from("5555555")), + occupation_id: Some(String::from("11")), + industry_id: Some(String::from("11")), + removal_time: None, + }, + AccountProfile { + id: None, + account_name: String::from("AaronHill"), + description: Some(String::from("Shortwave radio operator")), + first_name: Some(String::from("Aaron")), + middle_name: Some(String::from("Baker")), + last_name: Some(String::from("Hill")), + country_name: String::from("United States of America"), + street_number: Some(String::from("2344")), + street_name: Some(String::from("Central Ave")), + floor_number: None, + unit_number: None, + city_name: String::from("Billings"), + county_name: Some(String::from("Yellowstone County")), + region_name: None, + state_name: String::from("Montana"), + postal_code: String::from("59102"), + latlng: Some(String::from("(45.769540, -108.575760)")), + email_address: String::from("aaron@address.xz"), + telephone_country_code: Some(String::from("1")), + telephone_area_code: Some(String::from("406")), + telephone_number: Some(String::from("5555555")), + occupation_id: Some(String::from("4")), + industry_id: Some(String::from("4")), + removal_time: None, + }, + ]) + } + + pub fn create_test_transaction() -> Transaction { + Transaction { + id: Some(String::from("1")), + rule_instance_id: None, + author: Some(String::from("GroceryStore")), + author_device_id: None, + author_device_latlng: None, + author_role: Some(AccountRole::Creditor), + equilibrium_time: None, + sum_value: String::from("21.800"), + transaction_items: TransactionItems(vec![ + TransactionItem { + id: Some(String::from("2")), + transaction_id: Some(String::from("1")), + item_id: String::from("bread"), + price: String::from("3.000"), + quantity: String::from("2"), + debitor_first: Some(false), + rule_instance_id: None, + rule_exec_ids: Some(vec![]), + unit_of_measurement: None, + units_measured: None, + debitor: String::from("JacobWebb"), + creditor: String::from("GroceryStore"), + debitor_profile_id: None, + creditor_profile_id: None, + debitor_approval_time: None, + creditor_approval_time: None, + debitor_rejection_time: None, + creditor_rejection_time: None, + debitor_expiration_time: None, + creditor_expiration_time: None, + approvals: Some(Approvals(vec![ + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("1")), + transaction_item_id: Some(String::from("2")), + account_name: String::from("JacobWebb"), + account_role: AccountRole::Debitor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("1")), + transaction_item_id: Some(String::from("2")), + account_name: String::from("GroceryStore"), + account_role: AccountRole::Creditor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + ])), + }, + TransactionItem { + id: Some(String::from("3")), + transaction_id: Some(String::from("1")), + item_id: String::from("milk"), + price: String::from("4.000"), + quantity: String::from("3"), + debitor_first: Some(false), + rule_instance_id: None, + rule_exec_ids: Some(vec![]), + unit_of_measurement: None, + units_measured: None, + debitor: String::from("JacobWebb"), + creditor: String::from("GroceryStore"), + debitor_profile_id: None, + creditor_profile_id: None, + debitor_approval_time: None, + creditor_approval_time: None, + debitor_rejection_time: None, + creditor_rejection_time: None, + debitor_expiration_time: None, + creditor_expiration_time: None, + approvals: Some(Approvals(vec![ + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("1")), + transaction_item_id: Some(String::from("3")), + account_name: String::from("JacobWebb"), + account_role: AccountRole::Debitor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("1")), + transaction_item_id: Some(String::from("3")), + account_name: String::from("GroceryStore"), + account_role: AccountRole::Creditor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + ])), + }, + ]), + } + } + + pub fn create_test_transaction_items() -> TransactionItems { + TransactionItems(vec![ + TransactionItem { + id: Some(String::from("2")), + transaction_id: Some(String::from("1")), + item_id: String::from("bread"), + price: String::from("3.000"), + quantity: String::from("2"), + debitor_first: Some(false), + rule_instance_id: None, + rule_exec_ids: Some(vec![]), + unit_of_measurement: None, + units_measured: None, + debitor: String::from("JacobWebb"), + creditor: String::from("GroceryStore"), + debitor_profile_id: None, + creditor_profile_id: None, + debitor_approval_time: None, + creditor_approval_time: None, + debitor_rejection_time: None, + creditor_rejection_time: None, + debitor_expiration_time: None, + creditor_expiration_time: None, + approvals: Some(Approvals(vec![ + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("1")), + transaction_item_id: Some(String::from("2")), + account_name: String::from("JacobWebb"), + account_role: AccountRole::Debitor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("1")), + transaction_item_id: Some(String::from("2")), + account_name: String::from("GroceryStore"), + account_role: AccountRole::Creditor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + ])), + }, + TransactionItem { + id: Some(String::from("3")), + transaction_id: Some(String::from("1")), + item_id: String::from("milk"), + price: String::from("4.000"), + quantity: String::from("3"), + debitor_first: Some(false), + rule_instance_id: None, + rule_exec_ids: Some(vec![]), + unit_of_measurement: None, + units_measured: None, + debitor: String::from("JacobWebb"), + creditor: String::from("GroceryStore"), + debitor_profile_id: None, + creditor_profile_id: None, + debitor_approval_time: None, + creditor_approval_time: None, + debitor_rejection_time: None, + creditor_rejection_time: None, + debitor_expiration_time: None, + creditor_expiration_time: None, + approvals: Some(Approvals(vec![ + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("1")), + transaction_item_id: Some(String::from("3")), + account_name: String::from("JacobWebb"), + account_role: AccountRole::Debitor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + Approval { + id: None, + rule_instance_id: None, + transaction_id: Some(String::from("1")), + transaction_item_id: Some(String::from("3")), + account_name: String::from("GroceryStore"), + account_role: AccountRole::Creditor, + device_id: None, + device_latlng: None, + approval_time: None, + rejection_time: None, + expiration_time: None, + }, + ])), + }, + ]) + } +} diff --git a/services/auto-confirm/src/main.rs b/services/auto-confirm/src/main.rs index 63179d29..673dd570 100644 --- a/services/auto-confirm/src/main.rs +++ b/services/auto-confirm/src/main.rs @@ -169,7 +169,7 @@ async fn func(event: LambdaEvent) -> Result Result { let client_request = event.0; - let svc = Service::new(pool.get_conn().await); + let conn = pool.get_conn().await; + + let svc = Service::new(&conn); let account = client_request.account_name; diff --git a/services/request-approve/src/main.rs b/services/request-approve/src/main.rs index 697fe66b..f0c218e0 100644 --- a/services/request-approve/src/main.rs +++ b/services/request-approve/src/main.rs @@ -20,7 +20,9 @@ async fn handle_event( ) -> Result, StatusCode> { let client_request = event.0; - let svc = Service::new(pool.get_conn().await); + let conn = pool.get_conn().await; + + let svc = Service::new(&conn); let request_id = client_request.id.parse::().unwrap(); diff --git a/services/request-by-id/src/main.rs b/services/request-by-id/src/main.rs index ecd15f6e..703ff744 100644 --- a/services/request-by-id/src/main.rs +++ b/services/request-by-id/src/main.rs @@ -20,7 +20,9 @@ async fn handle_event( ) -> Result, StatusCode> { let client_request = event.0; - let svc = Service::new(pool.get_conn().await); + let conn = pool.get_conn().await; + + let svc = Service::new(&conn); let request_id = client_request.id.parse::().unwrap(); diff --git a/services/request-create/src/main.rs b/services/request-create/src/main.rs index 5bf3b06a..d7680bef 100644 --- a/services/request-create/src/main.rs +++ b/services/request-create/src/main.rs @@ -6,7 +6,7 @@ use axum::{ }; use httpclient::HttpClient as Client; use pg::postgres::{ConnectionPool, DatabaseConnection, DB}; -use service::Service; +use service::{Service, TxService}; use shutdown::shutdown_signal; use std::{env, error::Error, net::ToSocketAddrs}; use thiserror::Error; @@ -101,9 +101,9 @@ async fn test_values(req: IntraTransaction) -> Result( rule_tested: IntraTransaction, - svc: &mut Service, + svc: &mut TxService<'a, DatabaseConnection>, ) -> Result { let accounts = rule_tested.transaction.transaction_items.list_accounts(); @@ -144,9 +144,11 @@ async fn handle_event( }) .unwrap(); - let mut svc = Service::new(pool.get_conn().await); + let mut tx_conn = pool.get_conn().await; - let inserted_transaction_request = create_request(rule_tested.clone(), &mut svc) + let mut tx_svc = TxService::new(&mut tx_conn); + + let inserted_transaction_request = create_request(rule_tested.clone(), &mut tx_svc) .await .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; @@ -154,6 +156,10 @@ async fn handle_event( let auth_account = rule_tested.clone().auth_account.unwrap(); let approver_role = rule_tested.transaction.author_role.unwrap(); + let conn = pool.get_conn().await; + + let svc = Service::new(&conn); + let approved_transaction_request = svc .approve(auth_account, approver_role, inserted_transaction_request) .await diff --git a/services/requests-by-account/src/main.rs b/services/requests-by-account/src/main.rs index 1df47818..7a831d77 100644 --- a/services/requests-by-account/src/main.rs +++ b/services/requests-by-account/src/main.rs @@ -20,7 +20,9 @@ async fn handle_event( ) -> Result, StatusCode> { let client_request = event.0; - let svc = Service::new(pool.get_conn().await); + let conn = pool.get_conn().await; + + let svc = Service::new(&conn); let account = client_request.account_name; diff --git a/services/rule/src/main.rs b/services/rule/src/main.rs index 9490e949..8d343822 100644 --- a/services/rule/src/main.rs +++ b/services/rule/src/main.rs @@ -21,8 +21,8 @@ mod rules; // used by lambda to test for service availability const READINESS_CHECK_PATH: &str = "READINESS_CHECK_PATH"; -async fn apply_transaction_item_rules( - svc: &Service, +async fn apply_transaction_item_rules<'a>( + svc: &'a Service<'a, DatabaseConnection>, role_sequence: RoleSequence, transaction_items: &TransactionItems, ) -> TransactionItems { @@ -112,8 +112,8 @@ async fn apply_transaction_item_rules( response } -async fn apply_approval_rules( - svc: &Service, +async fn apply_approval_rules<'a>( + svc: &'a Service<'a, DatabaseConnection>, role_sequence: RoleSequence, transaction_items: &mut TransactionItems, approval_time: &TZTime, @@ -206,7 +206,7 @@ async fn apply_rules( let conn = pool.get_conn().await; // create service with conn - let svc = Service::new(conn); + let svc = Service::new(&conn); let mut rule_applied_tr_items = apply_transaction_item_rules(&svc, role_sequence, &transaction_items).await; diff --git a/services/transaction-by-id/src/main.rs b/services/transaction-by-id/src/main.rs index de227652..d13e4d32 100644 --- a/services/transaction-by-id/src/main.rs +++ b/services/transaction-by-id/src/main.rs @@ -20,7 +20,9 @@ async fn handle_event( ) -> Result, StatusCode> { let client_request = event.0; - let svc = Service::new(pool.get_conn().await); + let conn = pool.get_conn().await; + + let svc = Service::new(&conn); let transaction_id = client_request.id.parse::().unwrap(); diff --git a/services/transactions-by-account/src/main.rs b/services/transactions-by-account/src/main.rs index 510e3a4d..dc72794c 100644 --- a/services/transactions-by-account/src/main.rs +++ b/services/transactions-by-account/src/main.rs @@ -20,7 +20,9 @@ async fn handle_event( ) -> Result, StatusCode> { let client_request = event.0; - let svc = Service::new(pool.get_conn().await); + let conn = pool.get_conn().await; + + let svc = Service::new(&conn); let account = client_request.account_name;