We can now create securities in the UI!!!!
This commit is contained in:
1 parent
048ac31c27
commit
4810603dd7
10 files changed
+141
-17
No files matched your search
@@ -106,6 +106,24 @@ CREATE TABLE IF NOT EXISTS cashed_cheques
|
|||||||
CONSTRAINT double_spending UNIQUE (drawer_user_id, cheque_number) -- no double spending
|
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
|
CREATE TABLE IF NOT EXISTS event_processing_statuses
|
||||||
(
|
(
|
||||||
value TEXT PRIMARY KEY
|
value TEXT PRIMARY KEY
|
||||||
|
|||||||
@@ -30,6 +30,6 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</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"%}
|
{%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">
|
<div class="uk-margin">
|
||||||
<label class="uk-form-label"> Emitter Account
|
<label class="uk-form-label"> Emitter Account
|
||||||
<select class="uk-select"
|
<select class="uk-select"
|
||||||
|
|||||||
+11
-1
@@ -8,7 +8,7 @@ use crate::db::external_id::SecurityId;
|
|||||||
use crate::util::{CustomResult, Error};
|
use crate::util::{CustomResult, Error};
|
||||||
use crate::util::Error::FuckingError;
|
use crate::util::Error::FuckingError;
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AccountType {
|
pub enum AccountType {
|
||||||
Checking,
|
Checking,
|
||||||
SecurityEmitter,
|
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{
|
impl ToString for AccountType{
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
+3
-1
@@ -32,15 +32,17 @@ pub struct WireTransferRequest {
|
|||||||
pub drawer_user_id: UserId,
|
pub drawer_user_id: UserId,
|
||||||
pub payee_account_id: AccountId,
|
pub payee_account_id: AccountId,
|
||||||
pub amount: i64,
|
pub amount: i64,
|
||||||
|
pub wire_transfer_number: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WireTransferRequest {
|
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 {
|
WireTransferRequest {
|
||||||
drawer_user_id: drawer.0,
|
drawer_user_id: drawer.0,
|
||||||
drawer_account_id: drawer.1,
|
drawer_account_id: drawer.1,
|
||||||
payee_account_id: payee.clone(),
|
payee_account_id: payee.clone(),
|
||||||
amount,
|
amount,
|
||||||
|
wire_transfer_number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+34
-10
@@ -1,9 +1,12 @@
|
|||||||
use rusqlite::{Connection, Transaction};
|
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::securities::create_security;
|
||||||
use crate::db::users::create_user;
|
use crate::db::users::create_user;
|
||||||
use crate::events::{CreateNewAccount, CreateNewSecurity, CreateNewUser, EmitSecurities, Event};
|
use crate::events::{CreateNewAccount, CreateNewSecurity, CreateNewUser, EmitSecurities, Event};
|
||||||
|
use crate::services::cash_wire_transfer_request;
|
||||||
use crate::util::{CustomResult, Error};
|
use crate::util::{CustomResult, Error};
|
||||||
|
|
||||||
fn process_create_new_security_event(
|
fn process_create_new_security_event(
|
||||||
@@ -12,8 +15,7 @@ fn process_create_new_security_event(
|
|||||||
) -> CustomResult<()> {
|
) -> CustomResult<()> {
|
||||||
let r = event.to_create_new_security().unwrap();
|
let r = event.to_create_new_security().unwrap();
|
||||||
let sec = create_security(tx, &r)?;
|
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(())
|
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<()> {
|
fn process_emit_securities_event(tx: &mut Transaction, event: EmitSecurities) -> CustomResult<()> {
|
||||||
// create_checking_account(&tx, &event.securityId, &event.userId)?;
|
let emitter_account = accounts::get_account_by_id(tx, &event.emitter_account)?;
|
||||||
println!("Here it goes > {:?}", event);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_event(conn: &mut Connection, event: Event) -> CustomResult<()> {
|
pub fn process_event(conn: &mut Connection, event: Event) -> CustomResult<()> {
|
||||||
let mut tx = conn.transaction().map_err(Error::SqlError)?;
|
let mut tx = conn.transaction().map_err(Error::SqlError)?;
|
||||||
match event {
|
let ret = match event {
|
||||||
Event::CreateNewSecurity(e) => process_create_new_security_event(&mut tx, e)?,
|
Event::CreateNewSecurity(e) => process_create_new_security_event(&mut tx, e),
|
||||||
Event::CreateNewUser(e) => process_create_new_user_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::CreateNewAccount(e) => process_create_new_account_event(&mut tx, e),
|
||||||
Event::EmitSecurities(e) => process_emit_securities_event(&mut tx, e)?,
|
Event::EmitSecurities(e) => process_emit_securities_event(&mut tx, e),
|
||||||
};
|
};
|
||||||
|
match ret {
|
||||||
|
Err(_) => {
|
||||||
|
tx.rollback().map_err(Error::SqlError)?;
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
Ok(_) => {
|
||||||
tx.commit().map_err(Error::SqlError)
|
tx.commit().map_err(Error::SqlError)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-1
@@ -8,7 +8,7 @@ pub struct CreateNewSecurity {
|
|||||||
pub security_type: String,
|
pub security_type: String,
|
||||||
pub symbol: String,
|
pub symbol: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub userId: UserId,
|
pub user_id: UserId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CreateNewSecurity {
|
impl CreateNewSecurity {
|
||||||
@@ -47,6 +47,8 @@ pub struct CreateNewAccount {
|
|||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
pub struct EmitSecurities {
|
pub struct EmitSecurities {
|
||||||
pub amount: i64,
|
pub amount: i64,
|
||||||
|
pub id: i64,
|
||||||
|
pub emitter: UserId,
|
||||||
pub emitter_account: AccountId,
|
pub emitter_account: AccountId,
|
||||||
pub payee_accounts: Vec<AccountId>,
|
pub payee_accounts: Vec<AccountId>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,48 @@ fn _transfer_wire_transfer_securities(
|
|||||||
wire_transfer_request.amount)
|
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(
|
fn _add_cheque_to_cashed_cheques_log(
|
||||||
tx: &Connection,
|
tx: &Connection,
|
||||||
cheque: &Cheque,
|
cheque: &Cheque,
|
||||||
@@ -172,6 +214,7 @@ fn cash_wire_transfer_request_unsafe(
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let (drawer_receipt, payee_receipt) = _transfer_wire_transfer_securities(&savepoint, wire_transfer)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +234,7 @@ fn cash_cheque(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cash_wire_transfer_request(
|
pub fn cash_wire_transfer_request(
|
||||||
tx: &mut Transaction,
|
tx: &mut Transaction,
|
||||||
wire_transfer: &WireTransferRequest,
|
wire_transfer: &WireTransferRequest,
|
||||||
) -> CustomResult<()> {
|
) -> CustomResult<()> {
|
||||||
@@ -496,7 +539,7 @@ mod test_wire_transfers {
|
|||||||
let mut tx = conn.transaction().unwrap();
|
let mut tx = conn.transaction().unwrap();
|
||||||
|
|
||||||
// let cheque = Cheque::new(security_emitter, payee, 1000, 99);
|
// 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)?;
|
cash_wire_transfer_request(&mut tx, &wire_transfer)?;
|
||||||
tx.commit().unwrap();
|
tx.commit().unwrap();
|
||||||
@@ -513,7 +556,7 @@ mod test_wire_transfers {
|
|||||||
let (mut conn, drawer, payee, payee_account) = setup_basic();
|
let (mut conn, drawer, payee, payee_account) = setup_basic();
|
||||||
let mut tx = conn.transaction().unwrap();
|
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)?;
|
cash_wire_transfer_request(&mut tx, &wire_transfer)?;
|
||||||
|
|
||||||
@@ -526,5 +569,20 @@ mod test_wire_transfers {
|
|||||||
Ok(())
|
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()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ pub use crate::services::_authentication::SessionService;
|
|||||||
pub use crate::services::_securities::SecurityService;
|
pub use crate::services::_securities::SecurityService;
|
||||||
pub use crate::services::_users::UserService;
|
pub use crate::services::_users::UserService;
|
||||||
pub use crate::services::_accounts::AccountService;
|
pub use crate::services::_accounts::AccountService;
|
||||||
|
pub use crate::services::_transactions::cash_wire_transfer_request;
|
||||||
|
|
||||||
mod _authentication;
|
mod _authentication;
|
||||||
mod _securities;
|
mod _securities;
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
#!/usr/bin/env bash
|
#!/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
|
exec cargo run -- -vvv wui run --port 9999 --enable-template-autoreload
|
||||||
Reference in new issue
Block a user