Skip to content

Commit 39a763e

Browse files
crispinkoechc12i
andauthored
Implement bill manager api (#66)
* Add bill manager onboarding api * Add bill manager onboard modify API * Add single invoicing API * Add single invoicing API tests * Clean up bill manager onboard modules and tests * Rename bill manager single invoice payload to just Payload<> * Remove unnecessary type annotations * Make 'due_date' for invoice type owned * Add bill manager bulk invoicing API * Add bill manager reconciliation API * Add cancel invoice API * Clean up bulk invoicing module to throw if invoices is None * Keep bill manager features under one 'bill_manager' feature flag * Update bill manager urls on our docs * Apply suggestions from code review Apply suggestions Co-authored-by: Collins Muriuki <[email protected]> * Rename res_msg and res_code; tie chrono dependency under bill_manager * Add function to add single invoices to bulk invoice builder * Update README.md * Add function to CancelInvoiceBuilder --------- Co-authored-by: Collins Muriuki <[email protected]>
1 parent 5ac17da commit 39a763e

23 files changed

+2066
-6
lines changed

.cargo/config.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[build]
2-
rustdoc = "rustdoc"
2+
rustdoc = "rustdoc"
33

44
[alias]
5-
t = ["test", "--all-features", "--no-fail-fast"]
5+
t = ["test", "--all-features", "--no-fail-fast"]

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ readme = "./README.md"
1010
license = "MIT"
1111

1212
[dependencies]
13-
chrono = {version = "0.4", optional = true, default-features = false, features = ["clock"] }
13+
chrono = {version = "0.4", optional = true, default-features = false, features = ["clock", "serde"] }
1414
openssl = {version = "0.10", optional = true}
1515
reqwest = {version = "0.11", features = ["json"]}
1616
serde = {version="1.0", features= ["derive"]}
@@ -29,6 +29,7 @@ default = [
2929
"account_balance",
3030
"b2b",
3131
"b2c",
32+
"bill_manager",
3233
"c2b_register",
3334
"c2b_simulate",
3435
"express_request",
@@ -38,6 +39,7 @@ default = [
3839
account_balance = ["dep:openssl"]
3940
b2b = ["dep:openssl"]
4041
b2c = ["dep:openssl"]
42+
bill_manager = ["dep:chrono"]
4143
c2b_register = []
4244
c2b_simulate = []
4345
express_request = ["dep:chrono"]

README.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,110 @@ let response = client
266266
assert!(response.is_ok())
267267
```
268268

269+
- Bill Manager Onboard
270+
271+
```rust,ignore
272+
let response = client
273+
.onboard()
274+
.callback_url("https://testdomain.com/true")
275+
276+
.logo("https://file.domain/file.png")
277+
.official_contact("0712345678")
278+
.send_reminders(SendRemindersTypes::Enable)
279+
.short_code("600496")
280+
.send()
281+
.await;
282+
assert!(response.is_ok())
283+
```
284+
285+
- Bill Manager Onboard Modify
286+
287+
```rust,ignore
288+
let response = client
289+
.onboard_modify()
290+
.callback_url("https://testdomain.com/true")
291+
292+
.short_code("600496")
293+
.send()
294+
.await;
295+
assert!(response.is_ok())
296+
```
297+
298+
- Bill Manager Bulk Invoice
299+
300+
```rust,ignore
301+
let response = client
302+
.bulk_invoice()
303+
.invoices(vec![
304+
Invoice {
305+
amount: 1000.0,
306+
account_reference: "John Doe",
307+
billed_full_name: "John Doe",
308+
billed_period: "August 2021",
309+
billed_phone_number: "0712345678",
310+
due_date: Utc::now(),
311+
external_reference: "INV2345",
312+
invoice_items: Some(
313+
vec![InvoiceItem {amount: 1000.0, item_name: "An item"}]
314+
),
315+
invoice_name: "Invoice 001"
316+
}
317+
])
318+
.send()
319+
.await;
320+
assert!(response.is_ok())
321+
```
322+
323+
- Bill Manager Single Invoice
324+
325+
```rust,ignore
326+
let response = client
327+
.single_invoice()
328+
.amount(1000.0)
329+
.account_reference("John Doe")
330+
.billed_full_name("John Doe")
331+
.billed_period("August 2021")
332+
.billed_phone_number("0712345678")
333+
.due_date(Utc::now())
334+
.external_reference("INV2345")
335+
.invoice_items(vec![
336+
InvoiceItem {amount: 1000.0, item_name: "An item"}
337+
])
338+
.invoice_name("Invoice 001")
339+
.send()
340+
.await;
341+
assert!(response.is_ok())
342+
```
343+
344+
- Bill Manager Reconciliation
345+
346+
```rust,ignore
347+
let response = client
348+
.reconciliation()
349+
.account_reference("John Doe")
350+
.external_reference("INV2345")
351+
.full_name("John Doe")
352+
.invoice_name("Invoice 001")
353+
.paid_amount(1000.0)
354+
.payment_date(Utc::now())
355+
.phone_number("0712345678")
356+
.transaction_id("TRANSACTION_ID")
357+
.send()
358+
.await;
359+
assert!(response.is_ok())
360+
```
361+
362+
- Bill Manager Cancel Invoice
363+
364+
```rust,ignore
365+
let response = client
366+
.cancel_invoice()
367+
.external_references(vec!["9KLSS011"])
368+
.send()
369+
.await;
370+
assert!(response.is_ok())
371+
```
372+
269373
More will be added progressively, pull requests welcome
270374

271375
## Author

src/client.rs

Lines changed: 183 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::environment::ApiEnvironment;
22
use crate::services::{
3-
AccountBalanceBuilder, B2bBuilder, B2cBuilder, C2bRegisterBuilder, C2bSimulateBuilder,
4-
MpesaExpressRequestBuilder, TransactionReversalBuilder, TransactionStatusBuilder,
3+
AccountBalanceBuilder, B2bBuilder, B2cBuilder, BulkInvoiceBuilder, C2bRegisterBuilder,
4+
C2bSimulateBuilder, CancelInvoiceBuilder, MpesaExpressRequestBuilder, OnboardBuilder,
5+
OnboardModifyBuilder, ReconciliationBuilder, SingleInvoiceBuilder, TransactionReversalBuilder,
6+
TransactionStatusBuilder,
57
};
68
use crate::{ApiError, MpesaError};
79
use openssl::base64;
@@ -184,6 +186,185 @@ impl<'mpesa, Env: ApiEnvironment> Mpesa<Env> {
184186
B2bBuilder::new(self, initiator_name)
185187
}
186188

189+
/// **Bill Manager Onboard Builder**
190+
///
191+
/// Creates a `OnboardBuilder` which allows you to opt in as a biller to the bill manager features.
192+
///
193+
/// See more from the Safaricom API docs [here](https://developer.safaricom.co.ke/APIs/BillManager)
194+
///
195+
/// # Example
196+
/// ```ignore
197+
/// let response = client
198+
/// .onboard()
199+
/// .callback_url("https://testdomain.com/true")
200+
/// .email("[email protected]")
201+
/// .logo("https://file.domain/file.png")
202+
/// .official_contact("0712345678")
203+
/// .send_reminders(SendRemindersTypes::Enable)
204+
/// .short_code("600496")
205+
/// .send()
206+
/// .await;
207+
/// ```
208+
#[cfg(feature = "bill_manager")]
209+
pub fn onboard(&'mpesa self) -> OnboardBuilder<'mpesa, Env> {
210+
OnboardBuilder::new(self)
211+
}
212+
213+
/// **Bill Manager Onboard Modify Builder**
214+
///
215+
/// Creates a `OnboardModifyBuilder` which allows you to opt in as a biller to the bill manager features.
216+
///
217+
/// See more from the Safaricom API docs [here](https://developer.safaricom.co.ke/APIs/BillManager)
218+
///
219+
/// # Example
220+
/// ```ignore
221+
/// let response = client
222+
/// .onboard_modify()
223+
/// .callback_url("https://testdomain.com/true")
224+
/// .email("[email protected]")
225+
/// .logo("https://file.domain/file.png")
226+
/// .official_contact("0712345678")
227+
/// .send_reminders(SendRemindersTypes::Enable)
228+
/// .short_code("600496")
229+
/// .send()
230+
/// .await;
231+
/// ```
232+
#[cfg(feature = "bill_manager")]
233+
pub fn onboard_modify(&'mpesa self) -> OnboardModifyBuilder<'mpesa, Env> {
234+
OnboardModifyBuilder::new(self)
235+
}
236+
237+
/// **Bill Manager Bulk Invoice Builder**
238+
///
239+
/// Creates a `BulkInvoiceBuilder` which allows you to send invoices to your customers in bulk.
240+
/// See more from the Safaricom API docs [here](https://developer.safaricom.co.ke/APIs/BillManager)
241+
///
242+
/// # Example
243+
/// ```ignore
244+
/// use chrone::prelude::Utc;
245+
///
246+
/// let response = client
247+
/// .bulk_invoice()
248+
///
249+
/// // Add multiple invoices at once
250+
/// .invoices(vec![
251+
/// Invoice {
252+
/// amount: 1000.0,
253+
/// account_reference: "John Doe",
254+
/// billed_full_name: "John Doe",
255+
/// billed_period: "August 2021",
256+
/// billed_phone_number: "0712345678",
257+
/// due_date: Utc::now(),
258+
/// external_reference: "INV2345",
259+
/// invoice_items: Some(
260+
/// vec![InvoiceItem {amount: 1000.0, item_name: "An item"}]
261+
/// ),
262+
/// invoice_name: "Invoice 001"
263+
/// }
264+
/// ])
265+
///
266+
/// // Add a single invoice
267+
/// .invoice(
268+
/// Invoice {
269+
/// amount: 1000.0,
270+
/// account_reference: "John Doe",
271+
/// billed_full_name: "John Doe",
272+
/// billed_period: "August 2021",
273+
/// billed_phone_number: "0712345678",
274+
/// due_date: Utc::now(),
275+
/// external_reference: "INV2345",
276+
/// invoice_items: Some(vec![InvoiceItem {
277+
/// amount: 1000.0,
278+
/// item_name: "An item",
279+
/// }]),
280+
/// invoice_name: "Invoice 001",
281+
/// }
282+
/// )
283+
/// .send()
284+
/// .await;
285+
/// ```
286+
#[cfg(feature = "bill_manager")]
287+
pub fn bulk_invoice(&'mpesa self) -> BulkInvoiceBuilder<'mpesa, Env> {
288+
BulkInvoiceBuilder::new(self)
289+
}
290+
291+
/// **Bill Manager Single Invoice Builder**
292+
///
293+
/// Creates a `SingleInvoiceBuilder` which allows you to create and send invoices to your customers.
294+
/// See more from the Safaricom API docs [here](https://developer.safaricom.co.ke/APIs/BillManager)
295+
///
296+
/// # Example
297+
/// ```ignore
298+
/// use chrono::prelude::Utc;
299+
///
300+
/// let response = client
301+
/// .single_invoice()
302+
/// .amount(1000.0)
303+
/// .account_reference("John Doe")
304+
/// .billed_full_name("John Doe")
305+
/// .billed_period("August 2021")
306+
/// .billed_phone_number("0712345678")
307+
/// .due_date(Utc::now())
308+
/// .external_reference("INV2345")
309+
/// .invoice_items(vec![
310+
/// InvoiceItem {amount: 1000.0, item_name: "An item"}
311+
/// ])
312+
/// .invoice_name("Invoice 001")
313+
/// .send()
314+
/// .await;
315+
/// ```
316+
#[cfg(feature = "bill_manager")]
317+
pub fn single_invoice(&'mpesa self) -> SingleInvoiceBuilder<'mpesa, Env> {
318+
SingleInvoiceBuilder::new(self)
319+
}
320+
321+
/// **Bill Manager Reconciliation Builder**
322+
///
323+
/// Creates a `ReconciliationBuilder` which enables your customers to receive e-receipts for payments made to your paybill account.
324+
/// See more from the Safaricom API docs [here](https://developer.safaricom.co.ke/APIs/BillManager)
325+
///
326+
/// # Example
327+
/// ```ignore
328+
/// use chrono::prelude::Utc;
329+
///
330+
/// let response = client
331+
/// .reconciliation()
332+
/// .account_reference("John Doe")
333+
/// .external_reference("INV2345")
334+
/// .full_name("John Doe")
335+
/// .invoice_name("Invoice 001")
336+
/// .paid_amount(1000.0)
337+
/// .payment_date(Utc::now())
338+
/// .phone_number("0712345678")
339+
/// .transaction_id("TRANSACTION_ID")
340+
/// .send()
341+
/// .await;
342+
/// ```
343+
#[cfg(feature = "bill_manager")]
344+
pub fn reconciliation(&'mpesa self) -> ReconciliationBuilder<'mpesa, Env> {
345+
ReconciliationBuilder::new(self)
346+
}
347+
348+
/// **Bill Manager Cancel Invoice Builder**
349+
///
350+
/// Creates a `CancelInvoiceBuilder` which allows you to recall a sent invoice.
351+
/// See more from the Safaricom API docs [here](https://developer.safaricom.co.ke/APIs/BillManager)
352+
///
353+
/// # Example
354+
/// ```ignore
355+
/// use chrono::prelude::Utc;
356+
///
357+
/// let response = client
358+
/// .cancel_invoice()
359+
/// .external_references(vec!["9KLSS011"])
360+
/// .send()
361+
/// .await;
362+
/// ```
363+
#[cfg(feature = "bill_manager")]
364+
pub fn cancel_invoice(&'mpesa self) -> CancelInvoiceBuilder<'mpesa, Env> {
365+
CancelInvoiceBuilder::new(self)
366+
}
367+
187368
/// **C2B Register builder**
188369
///
189370
/// Creates a `C2bRegisterBuilder` for registering URLs to the 3rd party shortcode.

0 commit comments

Comments
 (0)