Skip to content

Commit

Permalink
feat(bill-manager): Update cached dependency and refactor client code
Browse files Browse the repository at this point in the history
* Update cached dependency to version 0.52
* Refactor client code to conditionally include openssl-related imports based on feature flags
* Move Invoice and InvoiceItem structs to bill_manager module
  • Loading branch information
itsyaasir committed Jul 8, 2024
1 parent a590bcd commit bb2acae
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 54 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ transaction_status = ["dep:openssl"]


[dependencies]
cached = { version = "0.49", features = ["wasm", "async", "proc_macro"] }
cached = { version = "0.52", features = ["async", "proc_macro"] }
chrono = { version = "0.4", optional = true, default-features = false, features = [
"clock",
"serde",
Expand Down
56 changes: 51 additions & 5 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,29 @@ use std::cell::RefCell;
use std::time::Duration;

use cached::Cached;
#[cfg(any(
feature = "account_balance",
feature = "b2b",
feature = "b2c",
feature = "transaction_reversal",
feature = "transaction_status"
))]
use openssl::base64;
#[cfg(any(
feature = "account_balance",
feature = "b2b",
feature = "b2c",
feature = "transaction_reversal",
feature = "transaction_status"
))]
use openssl::rsa::Padding;
#[cfg(any(
feature = "account_balance",
feature = "b2b",
feature = "b2c",
feature = "transaction_reversal",
feature = "transaction_status"
))]
use openssl::x509::X509;
use reqwest::Client as HttpClient;
use secrecy::{ExposeSecret, Secret};
Expand All @@ -12,13 +33,31 @@ use serde::Serialize;

use crate::auth::AUTH;
use crate::environment::ApiEnvironment;
#[cfg(feature = "account_balance")]
use crate::services::AccountBalanceBuilder;
#[cfg(feature = "b2b")]
use crate::services::B2bBuilder;
#[cfg(feature = "b2c")]
use crate::services::B2cBuilder;
#[cfg(feature = "c2b_register")]
use crate::services::C2bRegisterBuilder;
#[cfg(feature = "c2b_simulate")]
use crate::services::C2bSimulateBuilder;
#[cfg(feature = "transaction_status")]
use crate::services::TransactionStatusBuilder;
#[cfg(feature = "bill_manager")]
use crate::services::{
AccountBalanceBuilder, B2bBuilder, B2cBuilder, BulkInvoiceBuilder, C2bRegisterBuilder,
C2bSimulateBuilder, CancelInvoiceBuilder, DynamicQR, DynamicQRBuilder, MpesaExpress,
MpesaExpressBuilder, MpesaExpressQuery, MpesaExpressQueryBuilder, OnboardBuilder,
OnboardModifyBuilder, ReconciliationBuilder, SingleInvoiceBuilder, TransactionReversal,
TransactionReversalBuilder, TransactionStatusBuilder,
BulkInvoiceBuilder, CancelInvoiceBuilder, OnboardBuilder, OnboardModifyBuilder,
ReconciliationBuilder, SingleInvoiceBuilder,
};
#[cfg(feature = "dynamic_qr")]
use crate::services::{DynamicQR, DynamicQRBuilder};
#[cfg(feature = "express")]
use crate::services::{
MpesaExpress, MpesaExpressBuilder, MpesaExpressQuery, MpesaExpressQueryBuilder,
};
#[cfg(feature = "transaction_reversal")]
use crate::services::{TransactionReversal, TransactionReversalBuilder};
use crate::{auth, MpesaError, MpesaResult, ResponseError};

/// Source: [test credentials](https://developer.safaricom.co.ke/test_credentials)
Expand Down Expand Up @@ -273,6 +312,13 @@ impl Mpesa {
///
/// # Errors
/// Returns `EncryptionError` variant of `MpesaError`
#[cfg(any(
feature = "account_balance",
feature = "b2b",
feature = "b2c",
feature = "transaction_reversal",
feature = "transaction_status"
))]
pub(crate) fn gen_security_credentials(&self) -> MpesaResult<String> {
let pem = self.certificate.as_bytes();
let cert = X509::from_pem(pem)?;
Expand Down
41 changes: 0 additions & 41 deletions src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::fmt::{Display, Formatter, Result as FmtResult};

use chrono::prelude::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};

Expand Down Expand Up @@ -105,46 +104,6 @@ impl Display for SendRemindersTypes {
}
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Invoice<'i> {
pub amount: f64,
pub account_reference: &'i str,
pub billed_full_name: &'i str,
pub billed_period: &'i str,
pub billed_phone_number: &'i str,
pub due_date: DateTime<Utc>,
pub external_reference: &'i str,
#[serde(skip_serializing_if = "Option::is_none")]
pub invoice_items: Option<Vec<InvoiceItem<'i>>>,
pub invoice_name: &'i str,
}

impl<'i> Display for Invoice<'i> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(
f,
"amount: {}, account_reference: {}, due_date: {}, invoice_name: {}",
self.amount,
self.account_reference,
self.due_date.format("%Y-%m-%d"),
self.invoice_name,
)
}
}

#[derive(Debug, Serialize)]
pub struct InvoiceItem<'i> {
pub amount: f64,
pub item_name: &'i str,
}

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

#[derive(Debug, Clone, Copy, Serialize)]
pub enum TransactionType {
/// Send Money(Mobile number).
Expand Down
7 changes: 7 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ pub enum MpesaError {
ParseError(#[from] serde_json::Error),
#[error("An error has occurred while retrieving an environmental variable")]
EnvironmentalVariableError(#[from] VarError),
#[cfg(any(
feature = "account_balance",
feature = "b2b",
feature = "b2c",
feature = "transaction_reversal",
feature = "transaction_status"
))]
#[error("An error has occurred while generating security credentials")]
EncryptionError(#[from] openssl::error::ErrorStack),
#[error("{0}")]
Expand Down
3 changes: 1 addition & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ pub mod validator;

pub use client::Mpesa;
pub use constants::{
CommandId, IdentifierTypes, Invoice, InvoiceItem, ResponseType, SendRemindersTypes,
TransactionType,
CommandId, IdentifierTypes, ResponseType, SendRemindersTypes, TransactionType,
};
pub use environment::ApiEnvironment;
pub use environment::Environment::{self, Production, Sandbox};
Expand Down
2 changes: 1 addition & 1 deletion src/services/bill_manager/bulk_invoice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

use serde::Deserialize;

use super::Invoice;
use crate::client::Mpesa;
use crate::constants::Invoice;
use crate::errors::{MpesaError, MpesaResult};

const BILL_MANAGER_BULK_INVOICE_API_URL: &str = "v1/billmanager-invoice/bulk-invoicing";
Expand Down
44 changes: 44 additions & 0 deletions src/services/bill_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,53 @@ mod onboard_modify;
mod reconciliation;
mod single_invoice;

use std::fmt::{Display, Formatter, Result as FmtResult};

pub use bulk_invoice::{BulkInvoiceBuilder, BulkInvoiceResponse};
pub use cancel_invoice::{CancelInvoiceBuilder, CancelInvoiceResponse};
use chrono::{DateTime, Utc};
pub use onboard::{OnboardBuilder, OnboardResponse};
pub use onboard_modify::{OnboardModifyBuilder, OnboardModifyResponse};
pub use reconciliation::{ReconciliationBuilder, ReconciliationResponse};
use serde::Serialize;
pub use single_invoice::{SingleInvoiceBuilder, SingleInvoiceResponse};

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Invoice<'i> {
pub amount: f64,
pub account_reference: &'i str,
pub billed_full_name: &'i str,
pub billed_period: &'i str,
pub billed_phone_number: &'i str,
pub due_date: DateTime<Utc>,
pub external_reference: &'i str,
#[serde(skip_serializing_if = "Option::is_none")]
pub invoice_items: Option<Vec<InvoiceItem<'i>>>,
pub invoice_name: &'i str,
}

impl<'i> Display for Invoice<'i> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(
f,
"amount: {}, account_reference: {}, due_date: {}, invoice_name: {}",
self.amount,
self.account_reference,
self.due_date.format("%Y-%m-%d"),
self.invoice_name,
)
}
}

#[derive(Debug, Serialize)]
pub struct InvoiceItem<'i> {
pub amount: f64,
pub item_name: &'i str,
}

impl<'i> Display for InvoiceItem<'i> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "amount: {}, item_name: {}", self.amount, self.item_name)
}
}
2 changes: 1 addition & 1 deletion src/services/bill_manager/single_invoice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
use chrono::prelude::{DateTime, Utc};
use serde::Deserialize;

use super::{Invoice, InvoiceItem};
use crate::client::Mpesa;
use crate::constants::{Invoice, InvoiceItem};
use crate::errors::{MpesaError, MpesaResult};

const BILL_MANAGER_SINGLE_INVOICE_API_URL: &str = "v1/billmanager-invoice/single-invoicing";
Expand Down
16 changes: 15 additions & 1 deletion src/services/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,27 @@
//! 9. [Transaction Status](https://developer.safaricom.co.ke/APIs/TransactionStatus)
//! 10. [Dynamic QR](https://developer.safaricom.co.ke/APIs/DynamicQRCode)
//! 11. [Express](https://developer.safaricom.co.ke/APIs/ExpressCheckout)
#[cfg(feature = "account_balance")]
mod account_balance;
#[cfg(feature = "b2b")]
mod b2b;
#[cfg(feature = "b2c")]
mod b2c;
#[cfg(feature = "bill_manager")]
mod bill_manager;
#[cfg(feature = "c2b_register")]
mod c2b_register;
#[cfg(feature = "c2b_simulate")]
mod c2b_simulate;
#[cfg(feature = "dynamic_qr")]
mod dynamic_qr;
#[cfg(feature = "express")]
mod express;
#[cfg(feature = "transaction_reversal")]
mod transaction_reversal;
#[cfg(feature = "transaction_status")]
mod transaction_status;

#[cfg(feature = "account_balance")]
Expand Down Expand Up @@ -53,4 +65,6 @@ pub use transaction_reversal::{
TransactionReversalResponse,
};
#[cfg(feature = "transaction_status")]
pub use transaction_status::{TransactionStatusBuilder, TransactionStatusResponse};
pub use transaction_status::{
TransactionStatusBuilder, TransactionStatusPayload, TransactionStatusResponse,
};
3 changes: 2 additions & 1 deletion tests/mpesa-rust/bill_manager_test/bulk_invoice_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use chrono::prelude::Utc;
use mpesa::{Invoice, InvoiceItem, MpesaError};
use mpesa::services::{Invoice, InvoiceItem};
use mpesa::MpesaError;
use serde_json::json;
use wiremock::matchers::{method, path};
use wiremock::{Mock, ResponseTemplate};
Expand Down
3 changes: 2 additions & 1 deletion tests/mpesa-rust/bill_manager_test/single_invoice_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use chrono::prelude::Utc;
use mpesa::{InvoiceItem, MpesaError};
use mpesa::services::InvoiceItem;
use mpesa::MpesaError;
use serde_json::json;
use wiremock::matchers::{method, path};
use wiremock::{Mock, ResponseTemplate};
Expand Down

0 comments on commit bb2acae

Please sign in to comment.