use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum InternalTransferState {
#[default]
Prepared,
Confirmed,
Cancelled,
WaitingForAdmin,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum TransferDirection {
#[default]
Payment,
Income,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum InternalTransferType {
#[default]
Subaccount,
User,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct InternalTransfer {
pub id: i64,
pub currency: String,
pub amount: f64,
pub direction: TransferDirection,
pub other_side: String,
pub state: InternalTransferState,
#[serde(rename = "type")]
pub transfer_type: InternalTransferType,
pub created_timestamp: i64,
pub updated_timestamp: i64,
}
impl InternalTransfer {
#[must_use]
pub fn is_confirmed(&self) -> bool {
self.state == InternalTransferState::Confirmed
}
#[must_use]
pub fn is_cancelled(&self) -> bool {
self.state == InternalTransferState::Cancelled
}
#[must_use]
pub fn is_pending(&self) -> bool {
matches!(
self.state,
InternalTransferState::Prepared | InternalTransferState::WaitingForAdmin
)
}
#[must_use]
pub fn is_payment(&self) -> bool {
self.direction == TransferDirection::Payment
}
#[must_use]
pub fn is_income(&self) -> bool {
self.direction == TransferDirection::Income
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TransfersResponse {
pub count: u32,
pub data: Vec<InternalTransfer>,
}
impl TransfersResponse {
#[must_use]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[must_use]
pub fn len(&self) -> usize {
self.data.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_internal_transfer_deserialization() {
let json = r#"{
"id": 2,
"created_timestamp": 1550579457727,
"updated_timestamp": 1550579457727,
"currency": "BTC",
"amount": 0.2,
"direction": "payment",
"other_side": "new_user_1_1",
"state": "confirmed",
"type": "subaccount"
}"#;
let transfer: InternalTransfer = serde_json::from_str(json).unwrap();
assert_eq!(transfer.id, 2);
assert_eq!(transfer.currency, "BTC");
assert!((transfer.amount - 0.2).abs() < f64::EPSILON);
assert_eq!(transfer.direction, TransferDirection::Payment);
assert_eq!(transfer.other_side, "new_user_1_1");
assert_eq!(transfer.state, InternalTransferState::Confirmed);
assert_eq!(transfer.transfer_type, InternalTransferType::Subaccount);
assert!(transfer.is_confirmed());
assert!(transfer.is_payment());
}
#[test]
fn test_transfers_response_deserialization() {
let json = r#"{
"count": 1,
"data": [{
"id": 2,
"created_timestamp": 1550579457727,
"updated_timestamp": 1550579457727,
"currency": "BTC",
"amount": 0.2,
"direction": "payment",
"other_side": "new_user_1_1",
"state": "confirmed",
"type": "subaccount"
}]
}"#;
let response: TransfersResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.count, 1);
assert_eq!(response.len(), 1);
assert!(!response.is_empty());
}
#[test]
fn test_transfer_state_helpers() {
let mut transfer = InternalTransfer {
id: 1,
currency: "BTC".to_string(),
amount: 1.0,
direction: TransferDirection::Payment,
other_side: "test".to_string(),
state: InternalTransferState::Prepared,
transfer_type: InternalTransferType::Subaccount,
created_timestamp: 0,
updated_timestamp: 0,
};
assert!(transfer.is_pending());
assert!(!transfer.is_confirmed());
assert!(!transfer.is_cancelled());
transfer.state = InternalTransferState::Confirmed;
assert!(!transfer.is_pending());
assert!(transfer.is_confirmed());
transfer.state = InternalTransferState::Cancelled;
assert!(transfer.is_cancelled());
}
}