Skip to content

fix: feature-gated imports #110

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Comment on lines +5 to 28
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be possible cleaned up by deriving a feature_locked! (better name needed) declarative macro

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"
))]
Comment on lines +315 to +321
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for this

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> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I see you've moved this from the constants module to the bill manager module. This works as I don't think any other API (apart from bill manager) uses the invoice construct 👍

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
Loading