26 个版本 (2 个稳定版)
1.1.0 | 2023年11月14日 |
---|---|
0.4.2 | 2021年6月22日 |
0.3.3 | 2021年3月29日 |
0.2.6 | 2020年11月22日 |
0.1.2 |
|
在 财务 类别中排名 #8
145KB
2.5K SLoC
mpesa-rust
关于
一个非官方的 Rust 封装,用于访问 M-Pesa 服务,基于 Safaricom API。
安装
Cargo.toml
[dependencies]
mpesa = { version = "1.1.0" }
可选地,您可以通过禁用默认功能来禁用整个 MPESA API 套件,以有条件地选择以下之一
b2b
b2c
account_balance
c2b_register
c2b_simulate
express_request
transaction_reversal
transaction_status
bill_manager
dynamic_qr
示例
[dependencies]
mpesa = { git = "1.1.0", default_features = false, features = ["b2b", "express_request"] }
在您的 lib 或二进制 crate 中
use mpesa::Mpesa;
使用方法
创建一个 Mpesa
客户端
您首先需要创建一个 Mpesa
实例(客户端)。您需要提供 CLIENT_KEY 和 CLIENT_SECRET。您可以从 这里 获取 Safaricom 沙盒环境的这些凭证。需要注意的是,这些凭证仅在沙盒环境中有效。要上线并获得生产密钥,请阅读文档 此处。
以下是如何实例化 Mpesa
的方法
use mpesa::{Mpesa, Environment};
let client = Mpesa::new(
env!("CLIENT_KEY"),
env!("CLIENT_SECRET"),
Environment::Sandbox,
);
assert!(client.is_connected().await)
由于 Environment
枚举实现了 FromStr
和 TryFrom
对于 String
和 &str
类型,您可以使用 Environment::from_str
或 Environment::try_from
来创建一个 Environment
类型。如果环境值存储在 .env
或其他配置文件中,这是理想的
use mpesa::{Mpesa, Environment};
use std::str::FromStr;
use std::convert::TryFrom;
let client0 = Mpesa::new(
env!("CLIENT_KEY"),
env!("CLIENT_SECRET"),
Environment::from_str("sandbox")? // "Sandbox" and "SANDBOX" also valid
);
assert!(client0.is_connected().await)
let client1 = Mpesa::new(
env!("CLIENT_KEY"),
env!("CLIENT_SECRET"),
Environment::try_from("production")? // "Production" and "PRODUCTION" also valid
);
assert!(client1.is_connected().await)
Mpesa
结构体的 environment
参数是对任何实现了 ApiEnvironment
特性的类型进行泛型。此特性期望为给定类型实现以下方法
pub trait ApiEnvironment {
fn base_url(&self) -> &str;
fn get_certificate(&self) -> &str;
}
此特性允许您创建自己的类型并将其传递给environment
参数。有了这个特性,您就可以通过从base_url
方法返回模拟服务器URI来模拟http请求(用于测试目的),并且可以使用自己的证书来签名选择MPESA API的请求,通过提供自己的get_certificate
实现。
请参阅下面的示例(以及这里查看如何为Environment
枚举实现此特性)
use mpesa::{Mpesa, ApiEnvironment};
use std::str::FromStr;
use std::convert::TryFrom;
pub struct MyCustomEnvironment;
impl ApiEnvironment for MyCustomEnvironment {
fn base_url(&self) -> &str {
// your base url here
"https://your_base_url.com"
}
fn get_certificate(&self) -> &str {
// your certificate here
r#"..."#
}
}
let client: Mpesa<MyCustomEnvironment> = Mpesa::new(
env!("CLIENT_KEY"),
env!("CLIENT_SECRET"),
MyCustomEnvironment // ✔ valid
);
//...
如果您打算在生产中使用,您需要在创建客户端后调用Mpesa
中的set_initiator_password
方法。在这里,您提供发起者密码,该密码将覆盖在沙箱中使用的默认密码"Safcom496!"
use mpesa::Mpesa;
let client = Mpesa::new(
env!("CLIENT_KEY"),
env!("CLIENT_SECRET"),
Environment::Sandbox,
);
client.set_initiator_password("new_password");
assert!(client.is_connected().await)
服务
以下服务目前可通过Mpesa
客户端作为返回构建器的函数提供:
- B2C
let response = client
.b2c("testapi496")
.party_a("600496")
.party_b("254708374149")
.result_url("https://testdomain.com/ok")
.timeout_url("https://testdomain.com/err")
.amount(1000)
.send()
.await;
assert!(response.is_ok())
- B2B
let response = client
.b2b("testapi496")
.party_a("600496")
.party_b("254708374149")
.result_url("https://testdomain.com/ok")
.timeout_url("https://testdomain.com/err")
.account_ref("254708374149")
.amount(1000)
.send()
.await;
assert!(response.is_ok())
- C2B 注册
let response = client
.c2b_register()
.short_code("600496")
.confirmation_url("https://testdomain.com/true")
.validation_url("https://testdomain.com/valid")
.send()
.await;
assert!(response.is_ok())
- C2B 模拟
let response = client
.c2b_simulate()
.short_code("600496")
.msisdn("254700000000")
.amount(1000)
.send()
.await;
assert!(response.is_ok())
- 账户余额
let response = client
.account_balance("testapi496")
.result_url("https://testdomain.com/ok")
.timeout_url("https://testdomain.com/err")
.party_a("600496")
.send()
.await;
assert!(response.is_ok())
- Mpesa Express 请求 / STK 推送 / Lipa na M-PESA 线上
let response = client
.express_request("174379")
.phone_number("254708374149")
.amount(500)
.callback_url("https://test.example.com/api")
.send()
.await;
assert!(response.is_ok())
- 交易撤销
let response = client
.transaction_reversal("testapi496")
.result_url("https://testdomain.com/ok")
.timeout_url("https://testdomain.com/err")
.transaction_id("OEI2AK4Q16")
.receiver_identifier_type(IdentifierTypes::ShortCode)
.amount(100.0)
.receiver_party("600111")
.send()
.await;
assert!(response.is_ok())
- 交易状态
let response = client
.transaction_status("testapi496")
.result_url("https://testdomain.com/ok")
.timeout_url("https://testdomain.com/err")
.transaction_id("OEI2AK4Q16")
.identifier_type(IdentifierTypes::ShortCode)
.party_a("600111")
.remarks("status")
.occasion("work")
.send()
.await;
assert!(response.is_ok())
- 账单管理器上线
let response = client
.onboard()
.callback_url("https://testdomain.com/true")
.email("[email protected]")
.logo("https://file.domain/file.png")
.official_contact("0712345678")
.send_reminders(SendRemindersTypes::Enable)
.short_code("600496")
.send()
.await;
assert!(response.is_ok())
- 账单管理器上线修改
let response = client
.onboard_modify()
.callback_url("https://testdomain.com/true")
.email("[email protected]")
.short_code("600496")
.send()
.await;
assert!(response.is_ok())
- 账单管理器批量发票
let response = client
.bulk_invoice()
.invoices(vec![
Invoice {
amount: 1000.0,
account_reference: "John Doe",
billed_full_name: "John Doe",
billed_period: "August 2021",
billed_phone_number: "0712345678",
due_date: Utc::now(),
external_reference: "INV2345",
invoice_items: Some(
vec![InvoiceItem {amount: 1000.0, item_name: "An item"}]
),
invoice_name: "Invoice 001"
}
])
.send()
.await;
assert!(response.is_ok())
- 账单管理器单张发票
let response = client
.single_invoice()
.amount(1000.0)
.account_reference("John Doe")
.billed_full_name("John Doe")
.billed_period("August 2021")
.billed_phone_number("0712345678")
.due_date(Utc::now())
.external_reference("INV2345")
.invoice_items(vec![
InvoiceItem {amount: 1000.0, item_name: "An item"}
])
.invoice_name("Invoice 001")
.send()
.await;
assert!(response.is_ok())
- 账单管理器对账
let response = client
.reconciliation()
.account_reference("John Doe")
.external_reference("INV2345")
.full_name("John Doe")
.invoice_name("Invoice 001")
.paid_amount(1000.0)
.payment_date(Utc::now())
.phone_number("0712345678")
.transaction_id("TRANSACTION_ID")
.send()
.await;
assert!(response.is_ok())
- 账单管理器取消发票
let response = client
.cancel_invoice()
.external_references(vec!["9KLSS011"])
.send()
.await;
assert!(response.is_ok())
- 动态二维码
let response = client
.dynamic_qr_code()
.amount(1000)
.ref_no("John Doe")
.size("300")
.merchant_name("John Doe")
.credit_party_identifier("600496")
.try_transaction_type("bg")
.unwrap()
.build()
.unwrap()
.send()
.await;
assert!(response.is_ok())
将逐步添加更多功能,欢迎提交拉取请求
作者
Collins Muriuki
- Twitter: @collinsmuriuki_
- 与Safaricom无关。
贡献
欢迎贡献、问题和特性请求!
请随意查看问题页面。您还可以查看贡献指南。
版权 © 2023 Collins Muriuki。
此项目遵循MIT许可证。
依赖项
~15–29MB
~453K SLoC