use reqwest::header::CONTENT_LENGTH;
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value, from_str};
use serde_with::serde_as;
use snafu::{OptionExt, ensure};
use crate::{
card::utils::card_request_handler,
errors,
errors::{
ApiError,
card::{CardError, CardResult},
},
session::{Client, Session},
utils::{
ApiModel,
consts::{CARD_GET_BILL_URL, CARD_GET_CARD_URL},
},
};
#[serde_as]
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Card {
#[serde(alias = "acctNo")]
#[serde_as(deserialize_as = "serde_with::PickFirst<(_, serde_with::DisplayFromStr)>")]
pub id: u64,
#[serde(alias = "acctAmt")]
pub amount: u64,
}
impl ApiModel for Card {}
#[serde_as]
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Bill {
#[serde(rename = "tranName")]
pub name: String,
#[serde(alias = "tranDt")]
pub date: String,
#[serde(alias = "mchAcctName")]
pub place: String,
#[serde(alias = "tranAmt")]
pub tran_amount: i64,
#[serde(alias = "acctAmt")]
#[serde_as(deserialize_as = "serde_with::DisplayFromStr")]
pub acc_amount: i64,
}
impl ApiModel for Bill {}
impl Card {
pub async fn fetch_self(client: &Client, session: &Session) -> CardResult<Card> {
let res = card_request_handler(client, session, |client| {
client.post(CARD_GET_CARD_URL).header(CONTENT_LENGTH, 0)
})
.await?;
let text = res.json::<String>().await?;
let mut json = from_str::<Map<String, Value>>(&text).map_err(|_| ApiError::Website {
msg: "Website response format incorrect".to_string(),
})?;
ensure!(
json.get("respCode").and_then(Value::as_str) == Some("0000"),
errors::WebsiteSnafu {
msg: json
.get("respInfo")
.and_then(Value::as_str)
.unwrap_or("No Website Error")
.to_string(),
}
);
json.get_mut("objs")
.and_then(Value::as_array_mut)
.and_then(|array| array.get_mut(0))
.map(Value::take)
.map(serde_json::from_value)
.whatever_context::<&str, ApiError<CardError>>("Website response format incorrect")?
.map_err(|err| ApiError::ModelParse {
msg: format!("Deserialize error: {}", err),
})
}
}
impl Card {
pub async fn fetch_bill(
&self,
client: &Client,
session: &Session,
start_date: impl AsRef<str>,
end_date: impl AsRef<str>,
page: u16,
row: u16,
) -> CardResult<Vec<Bill>> {
let res = card_request_handler(client, session, |client| {
client.post(CARD_GET_BILL_URL).form(&[
("sdate", start_date.as_ref()),
("edate", end_date.as_ref()),
("account", self.id.to_string().as_ref()),
("page", &page.to_string()),
("row", &row.to_string()),
])
})
.await?;
let mut json = res.json::<Map<String, Value>>().await?;
if let Some(Value::Array(data)) = json.get_mut("rows").map(Value::take) {
data.into_iter()
.map(serde_json::from_value)
.collect::<Result<_, serde_json::Error>>()
.map_err(|err| ApiError::ModelParse {
msg: format!("Deserialize error: {}", err),
})
} else {
Err(ApiError::Website {
msg: "Website response format incorrect".to_string(),
})
}
}
}