We can now create securities in the UI!!!!

This commit is contained in:
didier amyot committed 2023-04-05 13:48:58 -04:00
1 parent 048ac31c27
commit 4810603dd7
10 files changed
+147 -23

No files matched your search

+23 -5
View File
@@ -106,6 +106,24 @@ CREATE TABLE IF NOT EXISTS cashed_cheques
CONSTRAINT double_spending UNIQUE (drawer_user_id, cheque_number) -- no double spending
);
CREATE TABLE IF NOT EXISTS cached_wire_transfers
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
drawer_account_id INTEGER NOT NULL,
drawer_account_version INTEGER NOT NULL,
wire_transfer_request_number INTEGER NOT NULL,
amount INTEGER NOT NULL,
underlying_security INTEGER NOT NULL,
payee_account_id INTEGER NOT NULL,
payee_account_version INTEGER NOT NULL,
creation_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (underlying_security) REFERENCES securities (id),
FOREIGN KEY (drawer_account_id) REFERENCES accounts (id),
FOREIGN KEY (payee_account_id) REFERENCES accounts (id),
CONSTRAINT double_spending UNIQUE (drawer_account_id, wire_transfer_request_number) -- no double spending
);
CREATE TABLE IF NOT EXISTS event_processing_statuses
(
value TEXT PRIMARY KEY
@@ -119,11 +137,11 @@ VALUES ('processing'),
CREATE TABLE IF NOT EXISTS event_processing_log
(
id TEXT PRIMARY KEY,
event JSON,
status TEXT NOT NULL,
received_time DATETIME NOT NULL,
id TEXT PRIMARY KEY,
event JSON,
status TEXT NOT NULL,
received_time DATETIME NOT NULL,
completed_time DATETIME,
error_message TEXT NOT NULL DEFAULT '',
error_message TEXT NOT NULL DEFAULT '',
FOREIGN KEY (status) REFERENCES event_processing_statuses (value)
)
@@ -30,6 +30,6 @@
</label>
</div>
<input type="hidden" name="event.CreateNewSecurity.userId" value="{{ user.id }}">
<input type="hidden" name="event.CreateNewSecurity.user_id" value="{{ user.id }}">
{%include "partials/actions/submit_button.html"%}
@@ -1,3 +1,11 @@
<input type="hidden"
name="event.EmitSecurities.id"
value="7876">
<input type="hidden"
name="event.EmitSecurities.emitter"
value="{{ user.id }}">
<div class="uk-margin">
<label class="uk-form-label"> Emitter Account
<select class="uk-select"
+11 -1
View File
@@ -8,7 +8,7 @@ use crate::db::external_id::SecurityId;
use crate::util::{CustomResult, Error};
use crate::util::Error::FuckingError;
#[derive(PartialEq, Debug)]
#[derive(Debug)]
pub enum AccountType {
Checking,
SecurityEmitter,
@@ -31,6 +31,16 @@ impl AccountType {
}
}
impl PartialEq for AccountType {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(AccountType::SecurityEmitter, AccountType::SecurityEmitter) => true,
(AccountType::Checking, AccountType::Checking) => true,
_ => false,
}
}
}
impl ToString for AccountType{
fn to_string(&self) -> String {
match self {
+3 -1
View File
@@ -32,15 +32,17 @@ pub struct WireTransferRequest {
pub drawer_user_id: UserId,
pub payee_account_id: AccountId,
pub amount: i64,
pub wire_transfer_number: i64,
}
impl WireTransferRequest {
pub fn new(drawer: Drawer, payee: & AccountId, amount: i64) -> WireTransferRequest {
pub fn new(drawer: Drawer, payee: & AccountId, amount: i64, wire_transfer_number: i64) -> WireTransferRequest {
WireTransferRequest {
drawer_user_id: drawer.0,
drawer_account_id: drawer.1,
payee_account_id: payee.clone(),
amount,
wire_transfer_number
}
}
+35 -11
View File
@@ -1,9 +1,12 @@
use rusqlite::{Connection, Transaction};
use crate::db::accounts::{create_checking_account, create_security_emitter_account};
use crate::db::accounts;
use crate::db::accounts::{AccountType, create_checking_account, create_security_emitter_account};
use crate::db::cheques::{Drawer, WireTransferRequest};
use crate::db::securities::create_security;
use crate::db::users::create_user;
use crate::events::{CreateNewAccount, CreateNewSecurity, CreateNewUser, EmitSecurities, Event};
use crate::services::cash_wire_transfer_request;
use crate::util::{CustomResult, Error};
fn process_create_new_security_event(
@@ -12,8 +15,7 @@ fn process_create_new_security_event(
) -> CustomResult<()> {
let r = event.to_create_new_security().unwrap();
let sec = create_security(tx, &r)?;
create_security_emitter_account(&tx, &sec.id(), &event.userId)?;
create_security_emitter_account(&tx, &sec.id(), &event.user_id)?;
Ok(())
}
@@ -28,18 +30,40 @@ fn process_create_new_account_event(tx: &mut Transaction, event: CreateNewAccoun
}
fn process_emit_securities_event(tx: &mut Transaction, event: EmitSecurities) -> CustomResult<()> {
// create_checking_account(&tx, &event.securityId, &event.userId)?;
println!("Here it goes > {:?}", event);
let emitter_account = accounts::get_account_by_id(tx, &event.emitter_account)?;
if emitter_account.account_type() != & AccountType::SecurityEmitter {
return Err(Error::UserInputError("".to_string()));
}
let mut i: i64 = 0;
for payee_account_id in event.payee_accounts {
let drawer: Drawer = (event.emitter.clone(),
event.emitter_account.clone(),
emitter_account.security().id().clone());
let wtr = WireTransferRequest::new(drawer.clone(),
&payee_account_id,
event.amount,
event.id + i);
cash_wire_transfer_request(tx, &wtr)?;
i += 1;
}
Ok(())
}
pub fn process_event(conn: &mut Connection, event: Event) -> CustomResult<()> {
let mut tx = conn.transaction().map_err(Error::SqlError)?;
match event {
Event::CreateNewSecurity(e) => process_create_new_security_event(&mut tx, e)?,
Event::CreateNewUser(e) => process_create_new_user_event(&mut tx, e)?,
Event::CreateNewAccount(e) => process_create_new_account_event(&mut tx, e)?,
Event::EmitSecurities(e) => process_emit_securities_event(&mut tx, e)?,
let ret = match event {
Event::CreateNewSecurity(e) => process_create_new_security_event(&mut tx, e),
Event::CreateNewUser(e) => process_create_new_user_event(&mut tx, e),
Event::CreateNewAccount(e) => process_create_new_account_event(&mut tx, e),
Event::EmitSecurities(e) => process_emit_securities_event(&mut tx, e),
};
tx.commit().map_err(Error::SqlError)
match ret {
Err(_) => {
tx.rollback().map_err(Error::SqlError)?;
ret
}
Ok(_) => {
tx.commit().map_err(Error::SqlError)
}
}
}
+3 -1
View File
@@ -8,7 +8,7 @@ pub struct CreateNewSecurity {
pub security_type: String,
pub symbol: String,
pub name: String,
pub userId: UserId,
pub user_id: UserId,
}
impl CreateNewSecurity {
@@ -47,6 +47,8 @@ pub struct CreateNewAccount {
#[derive(Deserialize, Serialize, Debug)]
pub struct EmitSecurities {
pub amount: i64,
pub id: i64,
pub emitter: UserId,
pub emitter_account: AccountId,
pub payee_accounts: Vec<AccountId>,
}
+61 -3
View File
@@ -62,6 +62,48 @@ fn _transfer_wire_transfer_securities(
wire_transfer_request.amount)
}
fn _add_wire_transfer_request_to_wire_transfers_log(tx: &Connection,
cheque: &WireTransferRequest,
drawer_receipt: &accounts::AccountChangeReceipt,
payee_receipt: &accounts::AccountChangeReceipt) -> Result<(), Error> {
let q = "
INSERT INTO cached_wire_transfers(
drawer_account_id,
drawer_account_version,
payee_account_id,
payee_account_version,
wire_transfer_request_number,
amount,
underlying_security
)
VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7)
";
let params = params![
drawer_receipt.account_id,
drawer_receipt.version,
payee_receipt.account_id,
payee_receipt.version,
cheque.amount,
cheque.amount,
payee_receipt.security_id
];
let ret = tx.execute(q, params).map_err(Error::SqlError);
match ret {
Ok(_) => Ok(()),
Err(Error::SqlError(rusqlite::Error::SqliteFailure(
ffi::Error {
code: _,
extended_code: 2067,
},
_,
))) => Err(Error::DoubleSpendingError(format!(
"Wire transfer number {} has already been cached.",
cheque.amount
))),
Err(a) => Err(a),
}
}
fn _add_cheque_to_cashed_cheques_log(
tx: &Connection,
cheque: &Cheque,
@@ -172,6 +214,7 @@ fn cash_wire_transfer_request_unsafe(
)));
}
let (drawer_receipt, payee_receipt) = _transfer_wire_transfer_securities(&savepoint, wire_transfer)?;
_add_wire_transfer_request_to_wire_transfers_log(&savepoint, wire_transfer, &drawer_receipt, &payee_receipt)?;
Ok(())
}
@@ -191,7 +234,7 @@ fn cash_cheque(
}
}
fn cash_wire_transfer_request(
pub fn cash_wire_transfer_request(
tx: &mut Transaction,
wire_transfer: &WireTransferRequest,
) -> CustomResult<()> {
@@ -496,7 +539,7 @@ mod test_wire_transfers {
let mut tx = conn.transaction().unwrap();
// let cheque = Cheque::new(security_emitter, payee, 1000, 99);
let wire_transfer = WireTransferRequest::new(security_emitter, &payee_account, 1000);;
let wire_transfer = WireTransferRequest::new(security_emitter, &payee_account, 1000, 777);;
cash_wire_transfer_request(&mut tx, &wire_transfer)?;
tx.commit().unwrap();
@@ -513,7 +556,7 @@ mod test_wire_transfers {
let (mut conn, drawer, payee, payee_account) = setup_basic();
let mut tx = conn.transaction().unwrap();
let wire_transfer = WireTransferRequest::new(drawer.clone(), &payee_account, 25);
let wire_transfer = WireTransferRequest::new(drawer.clone(), &payee_account, 25, 989);
cash_wire_transfer_request(&mut tx, &wire_transfer)?;
@@ -526,5 +569,20 @@ mod test_wire_transfers {
Ok(())
}
#[test]
fn test_wire_transfer_double_spending() -> CustomResult<()> {
let (mut conn, drawer, payee, payee_account) = setup_basic();
let wire_transfer = WireTransferRequest::new(drawer.clone(), &payee_account, 25, 989);
let mut tx = conn.transaction().unwrap();
cash_wire_transfer_request(&mut tx, &wire_transfer)?;
tx.commit().unwrap();
let mut tx = conn.transaction().unwrap();
let ret = cash_wire_transfer_request(&mut tx, &wire_transfer);
match ret {
Err(Error::DoubleSpendingError(_)) => Ok(()),
_ => Err(Error::Testing("Expected DoubleSpendingError error".to_string()))
}
}
}
+1
View File
@@ -2,6 +2,7 @@ pub use crate::services::_authentication::SessionService;
pub use crate::services::_securities::SecurityService;
pub use crate::services::_users::UserService;
pub use crate::services::_accounts::AccountService;
pub use crate::services::_transactions::cash_wire_transfer_request;
mod _authentication;
mod _securities;
+1
View File
@@ -1,2 +1,3 @@
#!/usr/bin/env bash
cargo run users new --name didier.amyot@gmail.com --public-key fooof
exec cargo run -- -vvv wui run --port 9999 --enable-template-autoreload