Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update bill manager to latest api docs and use derive builder. #92

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Creates a `CancelInvoiceBuilder` which allows you to recall a sent invoice.
Creates a `CancelBulkInvoicesBuilder` which allows you to recall a list of sent invoices.

Safaricom API docs [reference](https://developer.safaricom.co.ke/APIs/BillManager)

Expand All @@ -18,7 +18,7 @@ async fn main() {
);

let response = client
.cancel_invoice()
.cancel_bulk_invoice()
.external_references(vec!["9KLSS011"])
.send()
.await;
Expand Down
30 changes: 30 additions & 0 deletions docs/client/bill_manager/cancel_single_invoice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Creates a `CancelSingleInvoiceBuilder` which allows you to recall a sent invoice.

Safaricom API docs [reference](https://developer.safaricom.co.ke/APIs/BillManager)

# Example
```rust,ignore
use mpesa::{Mpesa, Environment, SendRemindersTypes};
use chrono::prelude::Utc;

#[tokio::main]
async fn main() {
dotenv::dotenv().ok();

let client = Mpesa::new(
env!("CLIENT_KEY"),
env!("CLIENT_SECRET"),
Environment::Sandbox,
);

let response = client
.cancel_single_invoice()
.external_reference("9KLSS011")
.build()
.unwrap()
.send()
.await;

assert!(response.is_ok());
}
```
4 changes: 3 additions & 1 deletion docs/client/bill_manager/onboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ async fn main() {
.logo("https://file.domain/file.png")
.official_contact("0712345678")
.send_reminders(SendRemindersTypes::Enable)
.short_code("718003")
.short_code("600496")
.build()
.unwrap()
.send()
.await;

Expand Down
2 changes: 2 additions & 0 deletions docs/client/bill_manager/onboard_modify.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ async fn main() {
.official_contact("0712345678")
.send_reminders(SendRemindersTypes::Enable)
.short_code("600496")
.build()
.unwrap()
.send()
.await;

Expand Down
2 changes: 2 additions & 0 deletions docs/client/bill_manager/reconciliation.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ async fn main() {
.payment_date(Utc::now())
.phone_number("0712345678")
.transaction_id("TRANSACTION_ID")
.build()
.unwrap()
.send()
.await;

Expand Down
2 changes: 2 additions & 0 deletions docs/client/bill_manager/single_invoice.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ async fn main() {
InvoiceItem {amount: 1000.0, item_name: "An item"}
])
.invoice_name("Invoice 001")
.build()
.unwrap()
.send()
.await;

Expand Down
25 changes: 16 additions & 9 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ use crate::auth::AUTH;
use crate::environment::ApiEnvironment;
use crate::services::{
AccountBalanceBuilder, B2bBuilder, B2cBuilder, BulkInvoiceBuilder, C2bRegisterBuilder,
C2bSimulateBuilder, CancelInvoiceBuilder, DynamicQR, DynamicQRBuilder,
MpesaExpressRequestBuilder, OnboardBuilder, OnboardModifyBuilder, ReconciliationBuilder,
C2bSimulateBuilder, CancelBulkInvoicesBuilder, CancelSingleInvoice, CancelSingleInvoiceBuilder,
DynamicQR, DynamicQRBuilder, MpesaExpressRequestBuilder, Onboard, OnboardBuilder,
OnboardModify, OnboardModifyBuilder, Reconciliation, ReconciliationBuilder, SingleInvoice,
SingleInvoiceBuilder, TransactionReversalBuilder, TransactionStatusBuilder,
};
use crate::{auth, MpesaResult};
Expand Down Expand Up @@ -177,13 +178,13 @@ impl<'mpesa, Env: ApiEnvironment> Mpesa<Env> {
#[cfg(feature = "bill_manager")]
#[doc = include_str!("../docs/client/bill_manager/onboard.md")]
pub fn onboard(&'mpesa self) -> OnboardBuilder<'mpesa, Env> {
OnboardBuilder::new(self)
Onboard::builder(self)
}

#[cfg(feature = "bill_manager")]
#[doc = include_str!("../docs/client/bill_manager/onboard_modify.md")]
pub fn onboard_modify(&'mpesa self) -> OnboardModifyBuilder<'mpesa, Env> {
OnboardModifyBuilder::new(self)
OnboardModify::builder(self)
}

#[cfg(feature = "bill_manager")]
Expand All @@ -195,19 +196,25 @@ impl<'mpesa, Env: ApiEnvironment> Mpesa<Env> {
#[cfg(feature = "bill_manager")]
#[doc = include_str!("../docs/client/bill_manager/single_invoice.md")]
pub fn single_invoice(&'mpesa self) -> SingleInvoiceBuilder<'mpesa, Env> {
SingleInvoiceBuilder::new(self)
SingleInvoice::builder(self)
}

#[cfg(feature = "bill_manager")]
#[doc = include_str!("../docs/client/bill_manager/reconciliation.md")]
pub fn reconciliation(&'mpesa self) -> ReconciliationBuilder<'mpesa, Env> {
ReconciliationBuilder::new(self)
Reconciliation::builder(self)
}

#[cfg(feature = "bill_manager")]
#[doc = include_str!("../docs/client/bill_manager/cancel_invoice.md")]
pub fn cancel_invoice(&'mpesa self) -> CancelInvoiceBuilder<'mpesa, Env> {
CancelInvoiceBuilder::new(self)
#[doc = include_str!("../docs/client/bill_manager/cancel_bulk_invoices.md")]
pub fn cancel_bulk_invoices(&'mpesa self) -> CancelBulkInvoicesBuilder<'mpesa, Env> {
CancelBulkInvoicesBuilder::new(self)
}

#[cfg(feature = "bill_manager")]
#[doc = include_str!("../docs/client/bill_manager/cancel_single_invoice.md")]
pub fn cancel_single_invoice(&'mpesa self) -> CancelSingleInvoiceBuilder<'mpesa, Env> {
CancelSingleInvoice::builder(self)
}

#[cfg(feature = "c2b_register")]
Expand Down
14 changes: 13 additions & 1 deletion src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ impl<'i> Display for Invoice<'i> {
}
}

#[derive(Debug, Serialize)]
#[derive(Clone, Debug, Serialize)]
pub struct InvoiceItem<'i> {
pub amount: f64,
pub item_name: &'i str,
Expand All @@ -145,6 +145,18 @@ impl<'i> Display for InvoiceItem<'i> {
}
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CancelInvoice<'i> {
pub external_reference: &'i str,
}

impl<'i> Display for CancelInvoice<'i> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "external_reference: {}", self.external_reference)
}
}

#[derive(Debug, Clone, Copy, Serialize)]
pub enum TransactionType {
/// Send Money(Mobile number).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
#![doc = include_str!("../../../docs/client/bill_manager/cancel_invoice.md")]
#![doc = include_str!("../../../docs/client/bill_manager/cancel_bulk_invoices.md")]

use serde::{Deserialize, Serialize};
use serde::Deserialize;

use crate::client::Mpesa;
use crate::constants::CancelInvoice;
use crate::environment::ApiEnvironment;
use crate::errors::MpesaResult;

const BILL_MANAGER_CANCEL_INVOICE_API_URL: &str = "v1/billmanager-invoice/cancel-single-invoice";

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct CancelInvoicePayload<'mpesa> {
external_reference: &'mpesa str,
}
const BILL_MANAGER_CANCEL_BULK_INVOICES_API_URL: &str =
"v1/billmanager-invoice/cancel-bulk-invoices";

#[derive(Clone, Debug, Deserialize)]
pub struct CancelInvoiceResponse {
pub struct CancelBulkInvoicesResponse {
#[serde(rename(deserialize = "rescode"))]
pub response_code: String,
#[serde(rename(deserialize = "resmsg"))]
Expand All @@ -25,15 +21,15 @@ pub struct CancelInvoiceResponse {
}

#[derive(Debug)]
pub struct CancelInvoiceBuilder<'mpesa, Env: ApiEnvironment> {
pub struct CancelBulkInvoicesBuilder<'mpesa, Env: ApiEnvironment> {
client: &'mpesa Mpesa<Env>,
external_references: Vec<CancelInvoicePayload<'mpesa>>,
external_references: Vec<CancelInvoice<'mpesa>>,
}

impl<'mpesa, Env: ApiEnvironment> CancelInvoiceBuilder<'mpesa, Env> {
/// Creates a new Bill Manager Cancel invoice builder
pub fn new(client: &'mpesa Mpesa<Env>) -> CancelInvoiceBuilder<'mpesa, Env> {
CancelInvoiceBuilder {
impl<'mpesa, Env: ApiEnvironment> CancelBulkInvoicesBuilder<'mpesa, Env> {
/// Creates a new Bill Manager Cancel bulk invoices builder
pub fn new(client: &'mpesa Mpesa<Env>) -> CancelBulkInvoicesBuilder<'mpesa, Env> {
CancelBulkInvoicesBuilder {
client,
external_references: vec![],
}
Expand All @@ -43,39 +39,39 @@ impl<'mpesa, Env: ApiEnvironment> CancelInvoiceBuilder<'mpesa, Env> {
pub fn external_reference(
mut self,
external_reference: &'mpesa str,
) -> CancelInvoiceBuilder<'mpesa, Env> {
) -> CancelBulkInvoicesBuilder<'mpesa, Env> {
self.external_references
.push(CancelInvoicePayload { external_reference });
.push(CancelInvoice { external_reference });
self
}

/// Adds `external_references`
pub fn external_references(
mut self,
external_references: Vec<&'mpesa str>,
) -> CancelInvoiceBuilder<'mpesa, Env> {
) -> CancelBulkInvoicesBuilder<'mpesa, Env> {
self.external_references.append(
&mut external_references
.into_iter()
.map(|external_reference| CancelInvoicePayload { external_reference })
.map(|external_reference| CancelInvoice { external_reference })
.collect(),
);
self
}

/// Bill Manager Cancel Invoice API
/// Bill Manager Cancel Bulk Invoices API
///
/// Cancels a list of invoices by their `external_reference`
///
/// A successful request returns a `CancelInvoiceResponse` type
/// A successful request returns a `CancelBulkInvoicesResponse` type
///
/// # Errors
/// Returns an `MpesaError` on failure
pub async fn send(self) -> MpesaResult<CancelInvoiceResponse> {
pub async fn send(self) -> MpesaResult<CancelBulkInvoicesResponse> {
self.client
.send(crate::client::Request {
method: reqwest::Method::POST,
path: BILL_MANAGER_CANCEL_INVOICE_API_URL,
path: BILL_MANAGER_CANCEL_BULK_INVOICES_API_URL,
body: self.external_references,
})
.await
Expand Down
62 changes: 62 additions & 0 deletions src/services/bill_manager/cancel_single_invoice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use derive_builder::Builder;
use serde::Deserialize;

use crate::client::Mpesa;
use crate::constants::CancelInvoice;
use crate::environment::ApiEnvironment;
use crate::errors::{MpesaError, MpesaResult};

const BILL_MANAGER_SINGLE_INVOICE_API_URL: &str = "v1/billmanager-invoice/cancel-single-invoice";

#[derive(Clone, Debug, Deserialize)]
pub struct CancelSingleInvoiceResponse {
#[serde(rename(deserialize = "rescode"))]
pub response_code: String,
#[serde(rename(deserialize = "resmsg"))]
pub response_message: String,
#[serde(rename(deserialize = "Status_Message"))]
pub status_message: String,
}

#[derive(Builder, Clone, Debug)]
#[builder(build_fn(error = "MpesaError"))]
pub struct CancelSingleInvoice<'mpesa, Env: ApiEnvironment> {
#[builder(pattern = "immutable", private)]
client: &'mpesa Mpesa<Env>,

#[builder(setter(into), try_setter)]
external_reference: &'mpesa str,
}

impl<'mpesa, Env: ApiEnvironment> From<CancelSingleInvoice<'mpesa, Env>> for CancelInvoice<'mpesa> {
fn from(builder: CancelSingleInvoice<'mpesa, Env>) -> Self {
CancelInvoice {
external_reference: builder.external_reference,
}
}
}

impl<'mpesa, Env: ApiEnvironment> CancelSingleInvoice<'mpesa, Env> {
pub(crate) fn builder(client: &'mpesa Mpesa<Env>) -> CancelSingleInvoiceBuilder<'mpesa, Env> {
CancelSingleInvoiceBuilder::default().client(client)
}

/// Bill Manager Cancel Single Invoice API
///
/// Cancels an invoice by its `external_reference`
///
/// A successful request returns a `CancelSingleInvoiceResponse` type
///
/// # Errors
/// Returns an `MpesaError` on failure
#[allow(clippy::unnecessary_lazy_evaluations)]
pub async fn send(self) -> MpesaResult<CancelSingleInvoiceResponse> {
self.client
.send::<CancelInvoice, _>(crate::client::Request {
method: reqwest::Method::POST,
path: BILL_MANAGER_SINGLE_INVOICE_API_URL,
body: self.into(),
})
.await
}
}
16 changes: 10 additions & 6 deletions src/services/bill_manager/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
mod bulk_invoice;
mod cancel_invoice;
mod cancel_bulk_invoices;
mod cancel_single_invoice;
mod onboard;
mod onboard_modify;
mod reconciliation;
mod single_invoice;

pub use bulk_invoice::{BulkInvoiceBuilder, BulkInvoiceResponse};
pub use cancel_invoice::{CancelInvoiceBuilder, CancelInvoiceResponse};
pub use onboard::{OnboardBuilder, OnboardResponse};
pub use onboard_modify::{OnboardModifyBuilder, OnboardModifyResponse};
pub use reconciliation::{ReconciliationBuilder, ReconciliationResponse};
pub use single_invoice::{SingleInvoiceBuilder, SingleInvoiceResponse};
pub use cancel_bulk_invoices::{CancelBulkInvoicesBuilder, CancelBulkInvoicesResponse};
pub use cancel_single_invoice::{
CancelSingleInvoice, CancelSingleInvoiceBuilder, CancelSingleInvoiceResponse,
};
pub use onboard::{Onboard, OnboardBuilder, OnboardResponse};
pub use onboard_modify::{OnboardModify, OnboardModifyBuilder, OnboardModifyResponse};
pub use reconciliation::{Reconciliation, ReconciliationBuilder, ReconciliationResponse};
pub use single_invoice::{SingleInvoice, SingleInvoiceBuilder, SingleInvoiceResponse};
Loading
Loading