1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use anyhow::Result;
use http::Method;
use std::sync::Arc;

use crate::{qs_params, session::CallbackProvider, Product, Session, SortOrder, Store};

pub struct Api<T: Store> {
  session: Arc<Session<T>>,
}

impl<T> Api<T>
where
  T: Store,
{
  pub fn new(session: Arc<Session<T>>) -> Self {
    Self { session }
  }

  pub async fn list<'a>(
    &self,
    account_id_key: &'a str,
    params: ListTransactionsRequest<'a>,
    callbacks: impl CallbackProvider,
  ) -> Result<TransactionListResponse> {
    let orders: serde_json::Value = self
      .session
      .send(
        Method::GET,
        format!("/v1/accounts/{}/transactions", account_id_key),
        qs_params(&params)?,
        callbacks,
      )
      .await?;
    debug!("orders json: {}", serde_json::to_string_pretty(&orders)?);
    Ok(serde_json::from_value(
      orders.get("TransactionListResponse").unwrap().clone(),
    )?)
  }

  pub async fn details<'a>(
    &self,
    account_id_key: &'a str,
    tranid: &'a str,
    store_id: &'a str,
    callbacks: impl CallbackProvider,
  ) -> Result<TransactionDetailsResponse> {
    let orders: serde_json::Value = self
      .session
      .send(
        Method::GET,
        format!("/v1/accounts/{}/transactions/{}", account_id_key, tranid),
        if store_id.is_empty() {
          None
        } else {
          Some(vec![("storeId", store_id)])
        },
        callbacks,
      )
      .await?;
    debug!("orders json: {}", serde_json::to_string_pretty(&orders)?);
    Ok(serde_json::from_value(
      orders.get("TransactionDetailsResponse").unwrap().clone(),
    )?)
  }
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct ListTransactionsRequest<'a> {
  pub start_date: Option<&'a str>,
  pub end_date: Option<&'a str>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub sort_order: Option<SortOrder>,
  pub marker: Option<&'a str>,
  pub count: Option<usize>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct TransactionListResponse {
  pub page_marker: String,
  pub more_transactions: bool,
  pub transaction_count: usize,
  pub total_count: usize,
  #[serde(rename = "Transaction", skip_serializing_if = "Vec::is_empty")]
  pub transaction: Vec<TransactionDetailsResponse>,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct TransactionDetailsResponse {
  pub transaction_id: i64,
  pub account_id: String,
  pub tranaction_date: i64,
  pub postdate: i64,
  pub amount: f64,
  #[serde(rename = "Category", skip_serializing_if = "Option::is_none")]
  pub category: Option<Category>,
  #[serde(rename = "Brokerage", skip_serializing_if = "Option::is_none")]
  pub brokerage: Option<Brokerage>,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct Category {
  pub category_id: String,
  pub parent_id: String,
  pub category_name: String,
  pub parent_name: String,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct Brokerage {
  pub transaction_type: String,
  pub product: Product,
  pub quantity: f64,
  pub price: f64,
  pub settlement_currency: String,
  pub payment_currency: String,
  pub fee: f64,
  pub memo: String,
  pub check_no: String,
  pub order_no: String,
}

pub enum ListFormat {
  Xls,
  Xlx,
  Json,
  Xml,
}