use serde::{Deserialize, Serialize};
use crate::{ApiEnvironment, CommandId, IdentifierTypes, Mpesa, MpesaError, MpesaResult};
#[derive(Debug, Serialize)]
pub struct TransactionStatusPayload<'mpesa> {
#[serde(rename(serialize = "Initiator"))]
initiator: &'mpesa str,
#[serde(rename(serialize = "SecurityCredential"))]
security_credentials: &'mpesa str,
#[serde(rename(serialize = "CommandID"))]
command_id: CommandId,
#[serde(rename(serialize = "TransactionID"))]
transaction_id: &'mpesa str,
#[serde(rename = "PartyA")]
party_a: &'mpesa str,
#[serde(rename(serialize = "IdentifierType"))]
identifier_type: IdentifierTypes,
#[serde(rename(serialize = "ResultURL"))]
result_url: &'mpesa str,
#[serde(rename(serialize = "QueueTimeOutURL"))]
timeout_url: &'mpesa str,
#[serde(rename(serialize = "Remarks"))]
remarks: &'mpesa str,
#[serde(rename(serialize = "Occasion"))]
occasion: &'mpesa str,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionStatusResponse {
#[serde(rename(deserialize = "ConversationID"))]
pub conversation_id: String,
#[serde(rename(deserialize = "OriginatorConversationID"))]
pub originator_conversation_id: String,
#[serde(rename(deserialize = "ResponseDescription"))]
pub response_description: String,
}
#[derive(Debug)]
pub struct TransactionStatusBuilder<'mpesa, Env: ApiEnvironment> {
client: &'mpesa Mpesa<Env>,
initiator: &'mpesa str,
command_id: Option<CommandId>,
transaction_id: Option<&'mpesa str>,
party_a: Option<&'mpesa str>,
identifier_type: Option<IdentifierTypes>,
result_url: Option<&'mpesa str>,
timeout_url: Option<&'mpesa str>,
remarks: Option<&'mpesa str>,
occasion: Option<&'mpesa str>,
}
impl<'mpesa, Env: ApiEnvironment> TransactionStatusBuilder<'mpesa, Env> {
pub fn new(
client: &'mpesa Mpesa<Env>,
initiator: &'mpesa str,
) -> TransactionStatusBuilder<'mpesa, Env> {
TransactionStatusBuilder {
client,
initiator,
command_id: None,
transaction_id: None,
party_a: None,
identifier_type: None,
result_url: None,
timeout_url: None,
remarks: None,
occasion: None,
}
}
pub fn command_id(mut self, command_id: CommandId) -> Self {
self.command_id = Some(command_id);
self
}
pub fn transaction_id(mut self, transaction_id: &'mpesa str) -> Self {
self.transaction_id = Some(transaction_id);
self
}
pub fn party_a(mut self, party_a: &'mpesa str) -> Self {
self.party_a = Some(party_a);
self
}
pub fn identifier_type(mut self, identifier_type: IdentifierTypes) -> Self {
self.identifier_type = Some(identifier_type);
self
}
pub fn result_url(mut self, result_url: &'mpesa str) -> Self {
self.result_url = Some(result_url);
self
}
pub fn timeout_url(mut self, timeout_url: &'mpesa str) -> Self {
self.timeout_url = Some(timeout_url);
self
}
pub fn remarks(mut self, remarks: &'mpesa str) -> Self {
self.remarks = Some(remarks);
self
}
pub fn occasion(mut self, occasion: &'mpesa str) -> Self {
self.occasion = Some(occasion);
self
}
pub async fn send(self) -> MpesaResult<TransactionStatusResponse> {
let url = format!(
"{}/mpesa/transactionstatus/v1/query",
self.client.environment.base_url()
);
let credentials = self.client.gen_security_credentials()?;
let payload = TransactionStatusPayload {
initiator: self.initiator,
security_credentials: &credentials,
command_id: self.command_id.unwrap_or(CommandId::TransactionStatusQuery),
transaction_id: self
.transaction_id
.ok_or(MpesaError::Message("transaction_id is required"))?,
party_a: self
.party_a
.ok_or(MpesaError::Message("party_a is required"))?,
identifier_type: self.identifier_type.unwrap_or(IdentifierTypes::ShortCode),
result_url: self
.result_url
.ok_or(MpesaError::Message("result_url is required"))?,
timeout_url: self
.timeout_url
.ok_or(MpesaError::Message("timeout_url is required"))?,
remarks: self.remarks.unwrap_or(stringify!(None)),
occasion: self.occasion.unwrap_or(stringify!(None)),
};
let response = self
.client
.http_client
.post(&url)
.bearer_auth(self.client.auth().await?)
.json(&payload)
.send()
.await?;
if !response.status().is_success() {
let value = response.json().await?;
return Err(MpesaError::MpesaTransactionStatusError(value));
};
let response = response.json::<_>().await?;
Ok(response)
}
}