use crate::client::Client;
use crate::error::Result;
use serde::{Deserialize, Serialize};
pub struct AnalyticsApi {
client: Client,
waba_id: String,
}
impl AnalyticsApi {
pub(crate) fn new(client: Client, waba_id: String) -> Self {
Self { client, waba_id }
}
pub async fn get_conversation_analytics(
&self,
start: i64,
end: i64,
granularity: Granularity,
) -> Result<ConversationAnalyticsResponse> {
let url = format!(
"{}?start={}&end={}&granularity={}&fields=conversation_analytics",
self.client.endpoint_url(&self.waba_id),
start,
end,
granularity.as_str()
);
self.client.get(&url).await
}
pub async fn get_template_analytics(
&self,
start: i64,
end: i64,
granularity: Granularity,
template_ids: Option<Vec<&str>>,
) -> Result<TemplateAnalyticsResponse> {
let mut url = format!(
"{}?start={}&end={}&granularity={}&fields=template_analytics",
self.client.endpoint_url(&self.waba_id),
start,
end,
granularity.as_str()
);
if let Some(ids) = template_ids {
let ids_param = ids.join(",");
url.push_str(&format!("&template_ids={}", ids_param));
}
self.client.get(&url).await
}
pub async fn get_phone_number_analytics(
&self,
start: i64,
end: i64,
granularity: Granularity,
phone_numbers: Option<Vec<&str>>,
) -> Result<PhoneNumberAnalyticsResponse> {
let mut url = format!(
"{}?start={}&end={}&granularity={}&fields=analytics",
self.client.endpoint_url(&self.waba_id),
start,
end,
granularity.as_str()
);
if let Some(numbers) = phone_numbers {
let numbers_param = numbers.join(",");
url.push_str(&format!("&phone_numbers={}", numbers_param));
}
self.client.get(&url).await
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Granularity {
HalfHour,
Daily,
Monthly,
}
impl Granularity {
fn as_str(&self) -> &'static str {
match self {
Granularity::HalfHour => "HALF_HOUR",
Granularity::Daily => "DAILY",
Granularity::Monthly => "MONTHLY",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConversationAnalyticsResponse {
pub conversation_analytics: ConversationAnalytics,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConversationAnalytics {
pub data: Vec<ConversationDataPoint>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConversationDataPoint {
pub start: i64,
pub end: i64,
pub conversation: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub cost: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub phone_number: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub conversation_direction: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub conversation_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub conversation_category: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateAnalyticsResponse {
pub template_analytics: TemplateAnalytics,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateAnalytics {
pub data: Vec<TemplateDataPoint>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateDataPoint {
pub start: i64,
pub end: i64,
pub template_id: String,
#[serde(default)]
pub sent: i64,
#[serde(default)]
pub delivered: i64,
#[serde(default)]
pub read: i64,
#[serde(default)]
pub clicked: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PhoneNumberAnalyticsResponse {
pub analytics: PhoneNumberAnalytics,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PhoneNumberAnalytics {
pub phone_number: String,
pub data: Vec<PhoneNumberDataPoint>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PhoneNumberDataPoint {
pub start: i64,
pub end: i64,
#[serde(default)]
pub sent: i64,
#[serde(default)]
pub delivered: i64,
}