|
@@ -2,6 +2,7 @@ use crate::{
|
|
amount::AmountCents, transaction::*, AccountId, Amount, Asset, Batch, Payment, PaymentId,
|
|
amount::AmountCents, transaction::*, AccountId, Amount, Asset, Batch, Payment, PaymentId,
|
|
Status, Storage, TransactionId,
|
|
Status, Storage, TransactionId,
|
|
};
|
|
};
|
|
|
|
+use chrono::{DateTime, Utc};
|
|
use sha2::{Digest, Sha256};
|
|
use sha2::{Digest, Sha256};
|
|
use std::collections::HashMap;
|
|
use std::collections::HashMap;
|
|
|
|
|
|
@@ -41,6 +42,8 @@ pub struct Transaction {
|
|
create: Vec<Payment>,
|
|
create: Vec<Payment>,
|
|
status: Status,
|
|
status: Status,
|
|
is_external_deposit: bool,
|
|
is_external_deposit: bool,
|
|
|
|
+ created_at: DateTime<Utc>,
|
|
|
|
+ updated_at: DateTime<Utc>,
|
|
}
|
|
}
|
|
|
|
|
|
impl Transaction {
|
|
impl Transaction {
|
|
@@ -78,6 +81,8 @@ impl Transaction {
|
|
reference,
|
|
reference,
|
|
is_external_deposit: true,
|
|
is_external_deposit: true,
|
|
status,
|
|
status,
|
|
|
|
+ created_at: Utc::now(),
|
|
|
|
+ updated_at: Utc::now(),
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
@@ -96,10 +101,7 @@ impl Transaction {
|
|
)?;
|
|
)?;
|
|
|
|
|
|
for (i, input) in spend.iter().enumerate() {
|
|
for (i, input) in spend.iter().enumerate() {
|
|
- if input.spent_by.is_some() && input.spent_by.as_ref() != Some(&id) {
|
|
|
|
- return Err(Error::SpentPayment(i));
|
|
|
|
- }
|
|
|
|
- if input.spent_by.is_none() && input.status != Status::Settled {
|
|
|
|
|
|
+ if input.spent_by.as_ref() != Some(&id) && !input.is_spendable() {
|
|
return Err(Error::InvalidPaymentStatus(i, input.status.clone()));
|
|
return Err(Error::InvalidPaymentStatus(i, input.status.clone()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -133,6 +135,8 @@ impl Transaction {
|
|
create,
|
|
create,
|
|
is_external_deposit: false,
|
|
is_external_deposit: false,
|
|
status,
|
|
status,
|
|
|
|
+ created_at: Utc::now(),
|
|
|
|
+ updated_at: Utc::now(),
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
@@ -235,7 +239,10 @@ impl Transaction {
|
|
for (asset, credit_amount) in credit.into_iter() {
|
|
for (asset, credit_amount) in credit.into_iter() {
|
|
if let Some(debit_amount) = debit.remove(&asset) {
|
|
if let Some(debit_amount) = debit.remove(&asset) {
|
|
if debit_amount != credit_amount {
|
|
if debit_amount != credit_amount {
|
|
- return Err(Error::InvalidAmount(asset, debit_amount, credit_amount));
|
|
|
|
|
|
+ return Err(Error::InvalidAmount(
|
|
|
|
+ asset.new_amount(debit_amount),
|
|
|
|
+ asset.new_amount(credit_amount),
|
|
|
|
+ ));
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
return Err(Error::MissingSpendingAsset(asset));
|
|
return Err(Error::MissingSpendingAsset(asset));
|
|
@@ -269,6 +276,14 @@ impl Transaction {
|
|
&self.reference
|
|
&self.reference
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ pub fn created_at(&self) -> DateTime<Utc> {
|
|
|
|
+ self.created_at
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn updated_at(&self) -> DateTime<Utc> {
|
|
|
|
+ self.updated_at
|
|
|
|
+ }
|
|
|
|
+
|
|
pub async fn persist<'a, B, S>(&mut self, storage: &'a S) -> Result<(), Error>
|
|
pub async fn persist<'a, B, S>(&mut self, storage: &'a S) -> Result<(), Error>
|
|
where
|
|
where
|
|
B: Batch<'a>,
|
|
B: Batch<'a>,
|
|
@@ -281,12 +296,21 @@ impl Transaction {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
self.validate()?;
|
|
self.validate()?;
|
|
|
|
+ self.updated_at = Utc::now();
|
|
batch.store_transaction(self).await?;
|
|
batch.store_transaction(self).await?;
|
|
- batch.store_new_payments(&self.create).await?;
|
|
|
|
|
|
+ for payment in self.create.iter() {
|
|
|
|
+ batch.store_new_payment(payment).await?;
|
|
|
|
+ batch
|
|
|
|
+ .relate_account_to_transaction(&self.id, &payment.to)
|
|
|
|
+ .await?;
|
|
|
|
+ }
|
|
for input in self.spend.iter_mut() {
|
|
for input in self.spend.iter_mut() {
|
|
batch
|
|
batch
|
|
.spend_payment(&input.id, self.status.clone(), &self.id)
|
|
.spend_payment(&input.id, self.status.clone(), &self.id)
|
|
.await?;
|
|
.await?;
|
|
|
|
+ batch
|
|
|
|
+ .relate_account_to_transaction(&self.id, &input.to)
|
|
|
|
+ .await?;
|
|
}
|
|
}
|
|
batch.commit().await?;
|
|
batch.commit().await?;
|
|
Ok(())
|
|
Ok(())
|
|
@@ -304,6 +328,8 @@ impl TryFrom<from_db::Transaction> for Transaction {
|
|
create: value.create,
|
|
create: value.create,
|
|
reference: value.reference,
|
|
reference: value.reference,
|
|
status: value.status,
|
|
status: value.status,
|
|
|
|
+ created_at: value.created_at,
|
|
|
|
+ updated_at: value.updated_at,
|
|
};
|
|
};
|
|
tx.validate()?;
|
|
tx.validate()?;
|
|
Ok(tx)
|
|
Ok(tx)
|