atendwa / mpesa-artisan
一款专为Laravel项目设计的Laravel包,旨在无缝集成M-Pesa daraja API。
Requires
- php: ^8.2
- ext-openssl: *
Requires (Dev)
- larastan/larastan: ^2.0
- laravel/pint: ^1.16
- nunomaduro/collision: ^8.1.1||^7.10.0
- nunomaduro/phpinsights: ^2.11
- orchestra/testbench: ^9.0.0||^8.22.0
- pestphp/pest: ^2.34
- pestphp/pest-plugin-arch: ^2.7
- pestphp/pest-plugin-laravel: ^2.3
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^1.1
- phpstan/phpstan-phpunit: ^1.3
- spatie/laravel-ray: ^1.35
README
此Laravel包无缝集成M-Pesa支付服务,允许您轻松地在Laravel应用程序中处理M-Pesa交易。这是寻求可靠移动货币集成的企业和个人的完美解决方案。
带有一点魔力 🥳🤯
此包有很多优点,但我认为您最喜欢以下这些功能
-
使用IP白名单进行安全的回调:我们的
AllowWhitelistedMpesaIps
中间件通过验证发送回调的IP地址是否已列入白名单和有效,增加了额外的安全层。 -
我已为您实现了M-Pesa的
12/13
个API,方便您使用。第13个API即将到来!敬请期待更多功能。 🎉🚀 -
是的,您猜对了
drivers!
使用此包,您可以设置多个驱动来处理您的应用程序的不同M-Pesa凭据。只需将它们添加到mpesa.php配置文件中,然后您就可以开始使用了! 🚗💨stk()->driver('web-store')->amount(5); //... chain more methods stk()->driver('donation')->amount(80); //... chain more methods
-
我们的包包括一些有用的辅助类和函数,例如电话号码清理器、回调请求类等。此外,大多数类都有相应的全局辅助函数,以增加便利性! 🛠️🌟
$sanitise = new SanitisePhoneNumber(); $number = SanitisePhoneNumber::index('0712345678'); // returns 254712345678 //or $number = sanitise_phone_number('0712345678');
-
最后,为什么不试试
Route::callback()
宏呢?它允许您在路由文件中轻松设置回调路由。它处理IP白名单
并删除CSRF令牌验证
,使集成变得简单! 🚀✨Route::callback('/some-url', [SomeClass, 'do-something'])->name('name');
通过Composer安装
-
在终端中运行以下命令以安装此包
composer require atendwa/mpesa-artisan
-
发布配置文件
安装包后,使用以下Artisan命令发布配置文件
php artisan mpesa-artisan:install
发布的配置文件
配置文件
config/mpesa.php
应如下所示<?php return [ // This determines if the application is in 'sandbox' or 'live' mode 'environment' => env('MPESA_ENVIRONMENT', 'sandbox'), // These are the base URLs for sandbox and live environments 'urls' => [ 'sandbox' => env('MPESA_SANDBOX_URL', 'https://sandbox.safaricom.co.ke'), 'live' => env('MPESA_LIVE_URL', 'https://api.safaricom.co.ke'), ], // These are the various API endpoints used in the application 'endpoints' => [ 'access_token' => env('MPESA_ACCESS_TOKEN', 'oauth/v1/generate?grant_type=client_credentials'), 'account_balance' => env('MPESA_ACCOUNT_BALANCE_ENDPOINT', 'mpesa/accountbalance/v1/query'), 'transaction_status' => env('MPESA_TRANSACTION_STATUS', 'mpesa/transactionstatus/v1/query'), 'c2b_register_url' => env('MPESA_C2B_REGISTER_URL_ENDPOINT', 'mpesa/c2b/v2/registerurl'), 'business_buy_goods' => env('MPESA_BUSINESS_BUY_GOODS', 'mpesa/b2b/v1/paymentrequest'), 'b2b_express_checkout' => env('MPESA_B2B_EXPRESS_ENDPOINT', 'v1/ussdpush/get-msisdn'), 'business_pay_bill' => env('MPESA_BUSINESS_PAY_BILL', 'mpesa/b2b/v1/paymentrequest'), 'mpesa_express' => env('MPESA_EXPRESS_ENDPOINT', 'mpesa/stkpush/v1/processrequest'), 'stk_query' => env('MPESA_EXPRESS_QUERY_ENDPOINT', 'mpesa/stkpushquery/v1/query'), 'dynamic_qr' => env('MPESA_DYNAMIC_QR_ENDPOINT', 'mpesa/qrcode/v1/generate'), 'tax_remittance' => env('MPESA_TAX_REMITTANCE', 'mpesa/b2b/v1/remittax'), 'reversal' => env('MPESA_REVERSAL_ENDPOINT', 'mpesa/reversal/v1/request'), 'b2c' => env('MPESA_B2C_ENDPOINT', 'mpesa/b2c/v1/paymentrequest'), ], // Contains settings for different MPESA drivers 'drivers' => [ 'default' => [ 'initiator_name' => env('MPESA_INITIATOR_NAME', ''), 'passkey' => env('MPESA_PASSKEY', ''), 'security_credential' => env('MPESA_SECURITY_CREDENTIAL', ''), 'shortcodes' => [ 'business' => env('MPESA_BUSINESS_SHORTCODE', ''), 'payment' => env('MPESA_PAYMENT_SHORTCODE', ''), ], 'key_pairs' => [ 'consumer' => [ 'key' => env('MPESA_CONSUMER_KEY', ''), 'secret' => env('MPESA_CONSUMER_SECRET', ''), ], 'payment' => [ 'key' => env('MPESA_PAYMENT_CONSUMER_KEY', ''), 'secret' => env('MPESA_PAYMENT_CONSUMER_SECRET', ''), ], ], 'callbacks' => [ 'default' => env('MPESA_DEFAULT_CALLBACK', ''), 'default_timeout_url' => env('MPESA_DEFAULT_TIMEOUT_URL', ''), ], ], ], // Additional configuration settings 'configuration' => [ 'default_driver' => env('MPESA_DRIVER', 'default'), 'sanitise_phone_number' => env('SANITISE_PHONE_NUMBER', true), 'use_whitelist' => env('USE_IP_WHITELIST', true), ], // Cache settings for MPESA responses 'cache' => [ 'enabled' => env('MPESA_CACHE_ENABLED', true), 'prefix' => env('MPESA_CACHE_PREFIX', 'mpesa_artisan_cache'), ], // List of IPs allowed to access the application 'whitelisted_ips' => [ '196.201.214.200', '196.201.214.206', '196.201.213.114', '196.201.214.207', '196.201.214.208', '196. 201.213.44', '196.201.212.127', '196.201.212.138', '196.201.212.129', '196.201.212.136', '196.201.212.74', '196.201.212.69', ], ];
-
配置.env文件
使用必要的M-Pesa凭据更新您的
.env
文件MPESA_ENVIRONMENT="live" MPESA_INITIATOR_NAME="" MPESA_PASSKEY="" MPESA_SECURITY_CREDENTIAL="" MPESA_BUSINESS_SHORTCODE="" MPESA_PAYMENT_SHORTCODE="" MPESA_CONSUMER_KEY="" MPESA_CONSUMER_SECRET="" MPESA_PAYMENT_CONSUMER_KEY="" MPESA_PAYMENT_CONSUMER_SECRET="" MPESA_DEFAULT_CALLBACK="" MPESA_DEFAULT_TIMEOUT_URL=""
用法
在深入了解可用的API端点之前,让我们看看您如何轻松调用任何服务类。
// instantiate the class $stk = new STK(); $response = $stk->amount(34)->post(); // use the global helper stk()->amount(34)->post(); // use the Daraja Facade \Atendwa\MpesaArtisan\Facades\Daraja::stk()->amount(56)->post(); // use the daraja global helper daraja()->stk()->buyGoods()->amount(78)->post();
以下是一些需要注意的要点
-
所有API服务都提供了一个
driver('default')
方法来动态更改driver
。然而,您的自定义驱动必须与默认驱动的配置键匹配。如果驱动配置错误(例如,必须始终存在initiator_name
键),将抛出异常。 -
所有API服务还提供了一个
useConsumerKeyPair(true)
方法来在密钥对之间切换。默认情况下,使用consumer密钥对
。传递false
以使用payment
密钥,确保它们与提供的短代码匹配。不正确的密钥对可能会锁定您的安全凭据。 -
所有API服务都返回包含键在
camel case
中的Illuminate\Support\Collection
实例。例如,响应体中的ResponseCode
将转换为responseCode
。 -
amount()
方法仅接受整数
,而其他方法接受字符串
。 -
包中强制执行了
类型安全
。向方法传递无效类型将抛出异常或使用回退值。如果遇到无效的字符串类型,可以使用空字符串。 -
不同的API服务假设驱动、密钥对、备注、场合、短代码等默认值,因此您不需要调用每个方法。
$response = stk_query()->checkoutRequestID($id)->post();
-
每个API服务都指定了其有效负载的所需属性。如果任何必需属性为空,将抛出异常。
-
要使用不同的
API版本
,只需在您的.env
文件中覆盖所需端点的端点URL
。 -
电话号码应采用格式
254#########
。虽然该包不验证您传递的值,但您可以使用Atendwa\MpesaArtisan\Support\SanitisePhoneNumber
类或其全局辅助函数来帮助清理和转换电话号码到正确的格式。$number = sanitise_phone_number('0712345678'); // returns 25471234578 $number = sanitise_phone_number('+254712345678'); // returns 25471234578 $number = sanitise_phone_number('254712345678'); // returns 25471234578
1. 动态二维码
使用此API生成动态二维码,使拥有My Safaricom App或M-PESA应用的用户能够扫描二维码。他们可以捕获收银机号码和金额,并授权在选择的LIPA NA M-PESA(LNM)商户点支付商品和服务。
https://developer.safaricom.co.ke/APIs/DynamicQRCode
$response = dynamic_qr() ->driver('default') // Optional: Specify a custom driver ->useConsumerKeyPair(true) // Optional: Toggle key pairs, defaults to true for consumer key and secret ->amount(100) // Required: sets the 'Amount' attribute ->buyGoods() // Optional: defaults the TrxCode attribute to 'BG' // ->paybill() sets TrxCode to 'PB' // ->sendMoney() sets TrxCode to 'SM' // ->sendToBusiness() sets TrxCode to 'SB' // ->withdrawFromAgent() sets TrxCode to 'WA' ->size(400) // Optional: default is 300 ->merchantName('atendwa') // Required: sets the 'MerchantName' attribute ->reference('buy me a coffee') // Required: sets the 'RefNo' attribute ->creditPartyIdentifier('123456') // Required: sets the 'CreditPartyIdentifier (CPI)' attribute ->post();
2. M-Pesa Express 模拟(STK 推送)
Lipa na M-PESA在线API,也称为M-PESA Express(STK Push/NI 推送),简化了商户/企业发起的C2B(客户对企业)支付。
https://developer.safaricom.co.ke/APIs/MpesaExpressSimulate
$response = stk() ->driver('default') // Optional: Specify a custom driver ->useConsumerKeyPair(true) // Optional: Toggle key pairs, defaults to true for consumer key and secret ->partyB('1234567') // Optional: Specify a shortcode, defaults to the business shortcode ->buyGoods() // Optional: Choose between 'buyGoods' or 'payBill', defaults to 'buyGoods' // ->payBill() // Optional: Choose between 'buyGoods' or 'payBill', defaults to 'buyGoods' ->callbackUrl('https://tendwa.dev') // Required: Specify the callback URL ->phoneNumber('254712345678') // Required: Specify the customer's phone number ->amount(1) // Required: Specify the amount to be transacted ->reference('test') // Required: Specify an account reference ->description('test') // Required: Specify a transaction description ->post();
3. M-Pesa Express 查询(STK 查询)
使用此API检查Lipa Na M-PESA在线支付的状态。
https://developer.safaricom.co.ke/APIs/MpesaExpressQuery
$response = stk_query() ->driver('default') // Optional: defaults to 'default' ->useConsumerKeyPair(true) // Optional: defaults to true ->shortCode('1234567') // Optional: the package will attempt to use the business shortcode if not set ->checkoutRequestID($someID) // Required: The CheckoutRequestID from the STK push response ->post();
4. 客户对企业注册URL
注册URL API通过允许接收支付通知到您的paybill来补充客户对企业(C2B)API。此API允许您注册回调URL,通过这些URL您将收到支付到您的paybill/收银机号码的通知。
https://developer.safaricom.co.ke/APIs/CustomerToBusinessRegisterURL
$response = register_c2b_urls() ->driver('default') // Optional: Specify a custom driver ->useConsumerKeyPair(true) // Optional: Toggle key pairs, defaults to true for consumer key and secret ->shortCode('123456') // Required: Specify the short code ->completed() // Optional: the ResponseType is 'Completed' by default // ->cancelled() // Optional: sets the ResponseType attribute to 'Cancelled' ->confirmationUrl('https://tendwa.dev/package-sale/confirm') // Required: Specify the confirmation URL ->validationUrl('https://tendwa.dev/package-sale/validate') // Required: Specify the validation URL ->post();
5. 企业对客户(B2C)
B2C API允许企业直接向客户支付,例如工资支付、现金返还、促销支付、奖金、提款和贷款发放。
https://developer.safaricom.co.ke/APIs/BusinessToCustomer
$response = b2c() ->driver('default') // Optional: Specify a custom driver ->useConsumerKeyPair(false) // Optional: Toggle key pairs, defaults to true for consumer key and secret ->callbackUrl('https://tendwa.dev') // Required: Specify the callback URL ->timeoutUrl('https://tendwa.dev') // Required: Specify the timeout URL ->partyA('123456') ->partyB('254712345678') ->initiator('123456') // Optional: defaults to the initiator name in the config file ->amount(100) // Required: Specify the amount. Must be > 50 for safaricom to process the request ->remarks('test') // Required: Specify the transaction remarks ->occasion('test') // Required: Specify the transaction occasion ->post()
6. 交易状态
检查交易状态。
https://developer.safaricom.co.ke/APIs/TransactionStatus
$response = transaction_status() ->driver('default') // Optional: Specify a custom driver ->useConsumerKeyPair(false) // Optional: Toggle key pairs, defaults to true for consumer key and secret ->initiator('initiator') // Optional: defaults to the initiator name in the config file ->partyA('1234567') ->transactionID('NEF61H8J60') // Optional: use this if you have a transaction ID // ->originatorConversationID('AG_20190826_0000777ab7d848b9e721') // Optional: use this if you don't have a transaction ID ->timeoutUrl('https://tendwa.dev') // Required: Specify the timeout URL ->callbackUrl('https://tendwa.dev') // Required: Specify the callback URL ->remarks('Transaction status request.') // Optional: defaults to 'Transaction status request.' ->occasion('Transaction status request.') // Optional: defaults to 'Transaction status request.' ->post();
7. 账户余额
账户余额API用于请求短码的余额,适用于B2C、购买商品和支付账单账户。
https://developer.safaricom.co.ke/APIs/AccountBalance
$response = account_balance() ->driver('default') // Optional: Specify a custom driver ->useConsumerKeyPair(true) // Optional: Toggle key pairs, defaults to true for consumer key and secret ->partyA('123456') ->remarks('Get account balance.') // Optional: defaults to 'Get account balance.' ->timeoutUrl('https://tendwa.dev') // Required: Specify the timeout URL ->callbackUrl('https://tendwa.dev') // Required: Specify the callback URL ->post();
8. 冲销
https://developer.safaricom.co.ke/APIs/Reversal
$response = reversal() ->driver('default') // Optional: Specify a custom driver ->useConsumerKeyPair(true) // Optional: Toggle key pairs, defaults to true for consumer key and secret ->occasion('Transaction reversal request.') // Required: Specify the occasion transaction or defaults to 'Transaction reversal request.'. ->remarks('Transaction reversal request.') // Required: Specify the occasion transaction or defaults to 'Transaction reversal request.'. ->timeoutUrl('https://tendwa.dev') // Required: Specify the timeout URL ->callbackUrl('https://tendwa.dev') // Required: Specify the callback URL ->initiator('initiator') // Optional: defaults to the initiator name in the config file ->receiverParty('1234567') ->amount(100) // Required: Specify the amount ->transactionID('NEF61H8J60') // Optional: use this if you have a transaction ID ->post();
9. 税款缴纳
https://developer.safaricom.co.ke/APIs/TaxRemittance
$response = tax_remittance() ->driver('default') // Optional: Specify a custom driver ->useConsumerKeyPair(true) // Optional: Toggle key pairs, defaults to true for consumer key and secret ->initiator('initiator') // Optional: defaults to the initiator name in the config file ->callbackUrl('https://tendwa.dev') // Required: Specify the callback URL ->timeoutUrl('https://tendwa.dev') // Required: Specify the timeout URL ->partyA('1234567') // Required: Specify the shortcode ->partyB('572572') // Required: Specify the shortcode ->amount(100) // Required: Specify the amount ->remarks('Tax Remittance') // Optional: defaults to 'Tax Remittance' ->reference('Tax Remittance') // Optional: defaults to 'Tax Remittance' ->post();
10. 企业支付账单
https://developer.safaricom.co.ke/APIs/BusinessPayBill
$response = business_pay_bill() ->driver('default') // Optional: Specify a custom driver ->useConsumerKeyPair(true) // Optional: Toggle key pairs, defaults to true for consumer key and secret ->initiator('initiator') // Optional: defaults to the initiator name in the config file ->callbackUrl('https://tendwa.dev') // Required: Specify the callback URL ->timeoutUrl('https://tendwa.dev') // Required: Specify the timeout URL ->partyA('1234567') // Required: Specify the shortcode ->partyB('572572') // Required: Specify the shortcode ->amount(100) // Required: Specify the amount ->remarks('Business Payment') // Optional: defaults to 'Business Payment' ->reference('Business Payment') // Optional: defaults to 'Business Payment' ->post();
11. 企业购买商品
https://developer.safaricom.co.ke/APIs/BusinessBuyGoods
$response = business_buy_goods() ->driver('default') // Optional: Specify a custom driver ->useConsumerKeyPair(true) // Optional: Toggle key pairs, defaults to true for consumer key and secret ->initiator('initiator') // Optional: defaults to the initiator name in the config file ->callbackUrl('https://tendwa.dev') // Required: Specify the callback URL ->timeoutUrl('https://tendwa.dev') // Required: Specify the timeout URL ->partyA('1234567') // Required: Specify the shortcode ->partyB('572572') // Required: Specify the shortcode ->amount(100) // Required: Specify the amount ->remarks('Business Payment') // Optional: defaults to 'Business Payment' ->reference('Business Payment') // Optional: defaults to 'Business Payment' ->post();
12. B2B 快速结账
https://developer.safaricom.co.ke/APIs/B2BExpressCheckout
$response = b2b_express_checkout() ->driver('default') // Optional: Specify a custom driver ->useConsumerKeyPair(true) // Optional: Toggle key pairs, defaults to true for consumer key and secret ->primaryShortCode('1234567') // Required: Specify the primary short code ->receiverShortCode('572572') // Required: Specify the receiver short code ->amount(100) // Required: Specify the amount ->reference('Business Payment') // Required: Specify the reference ->callbackUrl('https://tendwa.dev') // Required: Specify the callback URL ->requestRefID($someUniqueID) // Required ->partnerName($yourStoreName) // Required ->post();
辅助工具
查看该包中包含的一些实用的辅助类
Mpesa 回调请求(MpesaCallbackRequest::class)
此类扩展了Laravel的HttpRequest类,并添加了解析M-Pesa回调结果和检查交易成功状态的功能。
-
Illuminate\Http\Request
类中的所有方法都可用。 -
fetchResponse()
方法自动解析响应体,允许您直接访问结果代码,而无需在嵌套数组中导航以访问不同回调类型(例如,STK、B2C)。
use Atendwa\MpesaArtisan\Http\Requests\MpesaCallbackRequest; public function handleStkCallback(MpesaCallbackRequest $request) { $response = $request->fetchResponse(); // returns the response body as a collection $response->get('resultCode'); // returns the result code from the response body // for stk push $response->get('merchantRequestID'); // for b2c $response->get('TransactionID'); // returns the result code from the response body $request->log(); // logs the response to your logging system with the info level $success = $request->successful(); // returns a boolean indicating if the transaction was successful by checking the result code }
清理电话号码(SanitisePhoneNumber::class)
此类清理电话号码,将它们转换成所需的格式。它有一个名为index
的方法,接受一个电话号码并返回清理后的版本。
$number = sanitise_phone_number('0712345678'); // returns 254712345678
解析响应(ParseResponse::class)
此类解析来自Safaricom的API响应。它有一个名为index
的方法,接受一个响应并返回一个解析后的版本。解析后的响应将具有camelCase
键、successfulResponse
和successfulResult
指示符表示成功,以及一个表示错误的hasErrors
键。此类用于内部以确保一致的响应解析。
$response = parse_response(stk()->post()); $response->get('successfulResponse'); // returns true if the response was successful $response->get('responseCode');