use serde::{Deserialize, Serialize};
use crate::client::Mpesa;
use crate::constants::CommandId;
use crate::environment::ApiEnvironment;
use crate::errors::{MpesaError, MpesaResult};
#[derive(Debug, Serialize)]
struct C2bSimulatePayload<'mpesa> {
#[serde(rename(serialize = "CommandID"))]
command_id: CommandId,
#[serde(rename(serialize = "Amount"))]
amount: f64,
#[serde(rename(serialize = "Msisdn"))]
msisdn: &'mpesa str,
#[serde(rename(serialize = "BillRefNumber"))]
bill_ref_number: &'mpesa str,
#[serde(rename(serialize = "ShortCode"))]
short_code: &'mpesa str,
}
#[derive(Debug, Clone, Deserialize)]
pub struct C2bSimulateResponse {
#[serde(
rename(deserialize = "ConversationID"),
skip_serializing_if = "Option::is_none"
)]
pub conversation_id: Option<String>,
#[serde(rename(deserialize = "OriginatorConversationID"))]
pub originator_conversation_id: String,
#[serde(rename(deserialize = "ResponseCode"))]
pub response_code: String,
#[serde(rename(deserialize = "ResponseDescription"))]
pub response_description: String,
}
#[derive(Debug)]
pub struct C2bSimulateBuilder<'mpesa, Env: ApiEnvironment> {
client: &'mpesa Mpesa<Env>,
command_id: Option<CommandId>,
amount: Option<f64>,
msisdn: Option<&'mpesa str>,
bill_ref_number: Option<&'mpesa str>,
short_code: Option<&'mpesa str>,
}
impl<'mpesa, Env: ApiEnvironment> C2bSimulateBuilder<'mpesa, Env> {
pub fn new(client: &'mpesa Mpesa<Env>) -> C2bSimulateBuilder<'mpesa, Env> {
C2bSimulateBuilder {
client,
command_id: None,
amount: None,
msisdn: None,
bill_ref_number: None,
short_code: None,
}
}
pub fn command_id(mut self, command_id: CommandId) -> C2bSimulateBuilder<'mpesa, Env> {
self.command_id = Some(command_id);
self
}
pub fn amount<Number: Into<f64>>(mut self, amount: Number) -> C2bSimulateBuilder<'mpesa, Env> {
self.amount = Some(amount.into());
self
}
pub fn msisdn(mut self, msisdn: &'mpesa str) -> C2bSimulateBuilder<'mpesa, Env> {
self.msisdn = Some(msisdn);
self
}
pub fn short_code(mut self, short_code: &'mpesa str) -> C2bSimulateBuilder<'mpesa, Env> {
self.short_code = Some(short_code);
self
}
pub fn bill_ref_number(
mut self,
bill_ref_number: &'mpesa str,
) -> C2bSimulateBuilder<'mpesa, Env> {
self.bill_ref_number = Some(bill_ref_number);
self
}
#[allow(clippy::unnecessary_lazy_evaluations)]
pub async fn send(self) -> MpesaResult<C2bSimulateResponse> {
let url = format!(
"{}/mpesa/c2b/v1/simulate",
self.client.environment.base_url()
);
let payload = C2bSimulatePayload {
command_id: self
.command_id
.unwrap_or_else(|| CommandId::CustomerPayBillOnline),
amount: self
.amount
.ok_or(MpesaError::Message("amount is required"))?,
msisdn: self
.msisdn
.ok_or(MpesaError::Message("msisdn is required"))?,
bill_ref_number: self
.bill_ref_number
.ok_or(MpesaError::Message("bill_ref_number is required"))?,
short_code: self
.short_code
.ok_or(MpesaError::Message("short_code is required"))?,
};
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 Ok(value);
}
let value = response.json().await?;
Err(MpesaError::C2bSimulateError(value))
}
}