前言:php
M-pesa:肯尼亞移動運營商Safaricom推出的手機銀行業務。是依託於手機SIM卡進行支付的。前端
官網:https://www.safaricom.co.ke/dealers/login.phpjava
開發者網站:https://developer.safaricom.co.ke/docs#going-liveandroid
正文:git
業務背景:公司須要在官網上加一個註冊爲經銷商的功能,其中有一個環節就是須要用戶支付必定的金錢。業務範圍是在肯尼亞。github
流程:apache
須要先在肯尼亞那邊註冊一個商戶帳號,那邊審批也要必定的時間,因此要提前去申請。經過以後,咱們能夠拿到商戶編號,密鑰等信息,它是有正式接口和測試接口的,能夠先用測試接口調試。json
後臺須要寫三個接口,一個是給前端的信息,一個是發送支付請求給Mpesa,一個是獲取Mpesa的支付狀態。api
前端須要在用戶點擊支付以後調用後臺的支付接口,而後不斷地請求後臺的支付狀態接口,直到獲取到狀態爲止。tomcat
用戶那邊的表現形式爲,手機上會收到一個支付的彈窗,會有金額數和商戶名稱,用戶輸入密碼便可完成支付。用戶支付超時,彈窗還在,此時輸入支付密碼是不會支付成功的。在彈窗關閉後,用戶在手機上是沒法主動再次調出彈窗的,也沒有相關的短信。
代碼:
//支付相關 @Service public class PaymentService { public static Logger logger = Logger.getLogger(PaymentService.class.getName()); @Autowired private IDistributorDao distributorDao; //更新經銷商信息 @Autowired private IPaymentBillDao paymentBillDao; //記錄訂單流水 /** 給前端顯示的商戶信息 * paymentVo:用戶名,支付手機號等(傳過來的手機號格式爲 區號手機號,前面不要加+號,中間不要加橫槓。254777777777) * PaybillVo:返回給前端的信息,訂單號,金額等 */ public ResultComplete<PaybillVo> getPaybill(PaymentVo paymentVo) { logger.info("getPaybill begin; info:%s" + paymentVo.toString()); PaybillVo info = new PaybillVo(); info.setPaybill(MpesaConfig.COMPANY_NAME); //商戶名稱(與用戶彈窗內的顯示一致) info.setPayAmount(BaseView.PAY_AMOUNT); //金額(貨幣類型爲肯尼亞先令) info.setOrderNo(this.getOrderNo()); //獲取訂單號 //處理支付流水。。。記錄相關信息到支付流水錶 return new ResultComplete<>(info); } //支付接口 public ResultComplete<String> payment(String payPhone, String orderNo) throws IOException { String amount = BaseView.PAY_AMOUNT; logger.info(String.format("payment begin; params: payPhone:%s, orderNo:%s", amount, payPhone, orderNo)); //調用M-pesa接口 String payInfo = Mpesa.STKPushSimulation(amount, payPhone, orderNo); //TODO test 測試的時候,由於我在國內,沒有辦法支付,因此把數據寫死了。 // 因爲是改造舊項目,工期比較緊,因此沒有進行配置,直接是註釋掉了,你們有時間能夠優化一下,這裏僅作參考 // String payInfo = "{" // + "\"MerchantRequestID\":\"6809-2590977-1\"," // + "\"CheckoutRequestID\":\"test\"," // + "\"ResponseCode\": \"0\"" // + "}"; Gson gson = new Gson(); Map map = gson.fromJson(payInfo, Map.class); String responseCode = (String) map.get("ResponseCode"); String checkoutRequestId = (String) map.get("CheckoutRequestID"); if (responseCode == null || Integer.parseInt(responseCode) != 0) { logger.error("payment request fail"); String payResultCode = responseCode; String payResultDesc = (String) map.get("CustomerMessage"); if (StringUtils.isBlank(responseCode)) { payResultCode = (String) map.get("errorCode"); payResultDesc = (String) map.get("errorMessage"); } //支付請求失敗時更新支付流水錶。。。 return new ResultComplete<>(false, 101, "支付請求失敗", null); } //因爲是舊項目的緣故,我用的session進行校驗。其實不是很方便,可改成存到Redis HttpSession session = HttpHelper.getSession(); session.setAttribute(BaseView.SESSION_PAY_KEY + orderNo, payInfo); session.setMaxInactiveInterval(0); //支付請求成功時更新支付流水錶。。。 logger.info("payment end"); return new ResultComplete<>(null); } //前端調用支付狀態 public ResultComplete<String> getPaymentStatus(String orderNo) throws IOException { logger.info(String.format("getPaymentStatus begin; params: orderNo:%s", orderNo)); //TODO test String checkoutRequestId = getCheckoutRequestId(orderNo); //獲取支付請求流水號 if (StringUtils.isBlank(checkoutRequestId)) { return new ResultComplete<>(false, 101, "未獲取支付請求信息", null); } String statusInfo = Mpesa.STKPushTransactionStatus(checkoutRequestId); // String statusInfo = "{" // + "\"MerchantRequestID\":\"6809-2590977-1\"," // + "\"CheckoutRequestID\":\"test\"," // + "\"ResponseCode\": \"0\"," // + "\"ResultCode\": \"0\"," // + "\"ResultDesc\": \"Success\"" // + "}"; Gson gson = new Gson(); Map map = gson.fromJson(statusInfo, Map.class); String responseCode = (String) map.get("ResponseCode"); String resultCode = (String) map.get("ResultCode"); String resultDesc = (String) map.get("ResultDesc"); if (responseCode == null || Integer.parseInt(responseCode) != 0 || resultCode == null || Integer.parseInt(resultCode) != 0) { logger.error("payment status fail"); String errorCode = (String) map.get("errorCode"); String errorMessage = (String) map.get("errorMessage"); if (errorCode != null && errorCode.equals("500.001.1001")) { return new ResultComplete<>(true, 201, "支付正在處理中", null); } String payResultCode = StringUtils.isNotBlank(resultCode) ? resultCode : errorCode; String payResultDesc = StringUtils.isNotBlank(resultDesc) ? resultDesc : errorMessage; //更新流水 return new ResultComplete<>(false, 102, "支付失敗", null); } HttpSession session = HttpHelper.getSession(); session.setAttribute(BaseView.SESSION_PAY_STATUS_KEY + orderNo, statusInfo); session.setMaxInactiveInterval(0); //更新流水 logger.info("getPaymentStatus end"); return new ResultComplete<>(null); } //獲取訂單號(我定義的是PAY-20190817-000001這樣,可本身視狀況而定) private String getOrderNo() { String nowDate = CalendarUtil.DtoSYmd(new Date()); String lastOrderNo = this.paymentBillDao.getLastOrderNo(nowDate); String orderNo = "PAY-" + nowDate + "-000001"; if (StringUtils.isNotBlank(lastOrderNo)) { String numberFmt = lastOrderNo.substring(lastOrderNo.length() - 6); //取最大編號後6位; String end = String.format("%06d", Integer.parseInt(numberFmt) + 1); orderNo = "PAY-" + nowDate + "-" + end; } return orderNo; } //獲取支付請求流水號 private String getCheckoutRequestId(String orderNo) { HttpSession session = HttpHelper.getSession(); String payInfo = String.valueOf(session.getAttribute(BaseView.SESSION_PAY_KEY + orderNo)); if (StringUtils.isBlank(payInfo) || payInfo.equals("null")) { return ""; } Gson gson = new Gson(); Map map = gson.fromJson(payInfo, Map.class); String responseCode = (String) map.get("ResponseCode"); if (responseCode == null || Integer.parseInt(responseCode) != 0) { return ""; } return (String) map.get("CheckoutRequestID"); } }
MpesaConfig(能夠考慮寫在配置文件)
public class MpesaConfig { /** * Connection timeout duration */ public static final int CONNECT_TIMEOUT = 60 * 1000; /** * Connection Read timeout duration */ public static final int READ_TIMEOUT = 60 * 1000; /** * Connection write timeout duration */ public static final int WRITE_TIMEOUT = 60 * 1000; /** * global topic to receive app wide push notifications */ public static final String TOPIC_GLOBAL = "global"; // broadcast receiver intent filters public static final String REGISTRATION_COMPLETE = "registrationComplete"; public static final String PUSH_NOTIFICATION = "pushNotification"; // id to handle the notification in the notification tray public static final int NOTIFICATION_ID = 100; public static final int NOTIFICATION_ID_BIG_IMAGE = 101; public static final String SHARED_PREF = "ah_firebase"; //STKPush Properties //public static final String BASE_URL = "https://sandbox.safaricom.co.ke"; //測試用的Base URL public static final String BASE_URL = "https://api.safaricom.co.ke"; //Base URL public static final String BUSINESS_SHORT_CODE = ""; //商戶編號 public static final String PASSKEY = ""; public static final String TRANSACTION_TYPE = "CustomerPayBillOnline"; public static final String PARTYB = ""; //收款賬號(通常與商戶編號一致) // 付款回調url ,驗證付款發送請求是否成功(非必須) public static final String CALLBACKURL = "http://www.*.com/pay/request/info?orderNo="; //密鑰 public static final String CONSUMER_KEY = ""; //secret public static final String CONSUMER_SECRET = ""; public static String AccessToken = null; //根據密鑰和secret得到,是有有效期的 }
Mpesa:
package com.mpesa; import java.io.IOException; import java.util.Base64; import org.apache.log4j.Logger; import com.google.gson.Gson; import com.mpesa.STKPush; import com.mpesa.STKPushTransactionStatusBean; import net.sf.json.JSONArray; import net.sf.json.JSONException; import net.sf.json.JSONObject; import com.mpesa.MpesaUtils; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; public class Mpesa { public static Logger logger = Logger.getLogger(Mpesa.class.getName()); static String appKey = MpesaConfig.CONSUMER_KEY; static String appSecret = MpesaConfig.CONSUMER_SECRET; // static String accessToken; // public Mpesa(String app_key, String app_secret) { // appKey = app_key; // appSecret = app_secret; // } /** * 獲取 AccessToken * * @return * @throws IOException */ public static String authenticate() throws IOException { logger.info("authenticate begin"); String app_key = appKey; String app_secret = appSecret; String appKeySecret = app_key + ":" + app_secret; byte[] bytes = appKeySecret.getBytes("ISO-8859-1"); String encoded = Base64.getEncoder().encodeToString(bytes); OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(MpesaConfig.BASE_URL + "/oauth/v1/generate?grant_type=client_credentials").get() .addHeader("authorization", "Basic " + encoded).addHeader("cache-control", "no-cache").build(); Response response = client.newCall(request).execute(); JSONObject jsonObject = null; String accessToken = null; try { // jsonObject = new JSONObject(response.body().string()); ResponseBody ss = response.body(); String info = ss.string(); logger.info("pay authenticate; info:%s" + info); jsonObject = JSONObject.fromObject(info); accessToken = jsonObject.getString("access_token"); MpesaConfig.AccessToken = accessToken; } catch (JSONException e) { e.printStackTrace(); } return accessToken; } public String C2BSimulation(String shortCode, String commandID, String amount, String MSISDN, String billRefNumber) throws IOException { if (MpesaConfig.AccessToken == null) { MpesaConfig.AccessToken = authenticate(); } JSONArray jsonArray = new JSONArray(); JSONObject jsonObject = new JSONObject(); try { jsonObject.put("ShortCode", shortCode); jsonObject.put("CommandID", commandID); jsonObject.put("Amount", amount); jsonObject.put("Msisdn", MSISDN); jsonObject.put("BillRefNumber", billRefNumber); } catch (JSONException e) { e.printStackTrace(); } jsonArray.add(jsonObject); String requestJson = jsonArray.toString().replaceAll("[\\[\\]]", ""); logger.info("C2BSimulation requestJson:" + requestJson); OkHttpClient client = new OkHttpClient(); MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, requestJson); Request request = new Request.Builder().url(MpesaConfig.BASE_URL + "/safaricom/c2b/v1/simulate").post(body) .addHeader("content-type", "application/json").addHeader("authorization", "Bearer " + MpesaConfig.AccessToken) .addHeader("cache-control", "no-cache").build(); Response response = client.newCall(request).execute(); String info = response.body().string(); logger.info("C2BSimulation end; info:" + info); return info; } public String B2CRequest(String initiatorName, String securityCredential, String commandID, String amount, String partyA, String partyB, String remarks, String queueTimeOutURL, String resultURL, String occassion) throws IOException { if (MpesaConfig.AccessToken == null) { MpesaConfig.AccessToken = authenticate(); } JSONArray jsonArray = new JSONArray(); JSONObject jsonObject = new JSONObject(); try { jsonObject.put("InitiatorName", initiatorName); jsonObject.put("SecurityCredential", securityCredential); jsonObject.put("CommandID", commandID); jsonObject.put("Amount", amount); jsonObject.put("PartyA", partyA); jsonObject.put("PartyB", partyB); jsonObject.put("Remarks", remarks); jsonObject.put("QueueTimeOutURL", queueTimeOutURL); jsonObject.put("ResultURL", resultURL); jsonObject.put("Occassion", occassion); } catch (JSONException e) { e.printStackTrace(); } jsonArray.add(jsonObject); String requestJson = jsonArray.toString().replaceAll("[\\[\\]]", ""); logger.info("B2CRequest requestJson:" + requestJson); OkHttpClient client = new OkHttpClient(); MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, requestJson); Request request = new Request.Builder().url(MpesaConfig.BASE_URL + "/mpesa/b2c/v1/paymentrequest").post(body) .addHeader("content-type", "application/json").addHeader("authorization", "Bearer " + MpesaConfig.AccessToken) .addHeader("cache-control", "no-cache").build(); Response response = client.newCall(request).execute(); String info = response.body().string(); logger.info("B2CRequest end; info:" + info); return info; } public String B2BRequest(String initiatorName, String accountReference, String securityCredential, String commandID, String senderIdentifierType, String receiverIdentifierType, float amount, String partyA, String partyB, String remarks, String queueTimeOutURL, String resultURL, String occassion) throws IOException { if (MpesaConfig.AccessToken == null) { MpesaConfig.AccessToken = authenticate(); } JSONArray jsonArray = new JSONArray(); JSONObject jsonObject = new JSONObject(); try { jsonObject.put("Initiator", initiatorName); jsonObject.put("SecurityCredential", securityCredential); jsonObject.put("CommandID", commandID); jsonObject.put("SenderIdentifierType", senderIdentifierType); jsonObject.put("RecieverIdentifierType", receiverIdentifierType); jsonObject.put("Amount", amount); jsonObject.put("PartyA", partyA); jsonObject.put("PartyB", partyB); jsonObject.put("Remarks", remarks); jsonObject.put("AccountReference", accountReference); jsonObject.put("QueueTimeOutURL", queueTimeOutURL); jsonObject.put("ResultURL", resultURL); } catch (JSONException e) { e.printStackTrace(); } jsonArray.add(jsonObject); String requestJson = jsonArray.toString().replaceAll("[\\[\\]]", ""); logger.info("B2BRequest requestJson:" + requestJson); OkHttpClient client = new OkHttpClient(); MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, requestJson); Request request = new Request.Builder().url(MpesaConfig.BASE_URL + "/safaricom/b2b/v1/paymentrequest") .post(body).addHeader("content-type", "application/json") .addHeader("authorization", "Bearer " + MpesaConfig.AccessToken).addHeader("cache-control", "no-cache") .build(); Response response = client.newCall(request).execute(); String info = response.body().string(); logger.info("B2BRequest end; info:" + info); return info; } /** * * @param amount * 金額 * @param phoneNumber * 手機號, * @param orderid * 訂單id * @return * @throws IOException */ public static String STKPushSimulation(String amount, String phoneNumber, String orderid) throws IOException { logger.info(String.format("pay request begin; amount:%s,phoneNumber:%s,orderid:%s", amount, phoneNumber, orderid)); logger.info("MpesaConfig.AccessToken:" + MpesaConfig.AccessToken); MpesaConfig.AccessToken = authenticate(); String timestamp = MpesaUtils.getTimestamp(); STKPush stkPush = new STKPush(MpesaConfig.BUSINESS_SHORT_CODE, MpesaUtils.getPassword(MpesaConfig.BUSINESS_SHORT_CODE, MpesaConfig.PASSKEY, timestamp), timestamp, MpesaConfig.TRANSACTION_TYPE, String.valueOf(amount), MpesaUtils.sanitizePhoneNumber(phoneNumber), MpesaConfig.PARTYB, MpesaUtils.sanitizePhoneNumber(phoneNumber), MpesaConfig.CALLBACKURL + orderid + "&phone_number=" + phoneNumber, "BFSumaOnLine", "test"); Gson gson = new Gson(); String requestJson = gson.toJson(stkPush); OkHttpClient client = new OkHttpClient(); String url = MpesaConfig.BASE_URL + "/mpesa/stkpush/v1/processrequest"; MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, requestJson); Request request = new Request.Builder().url(url).post(body).addHeader("content-type", "application/json") .addHeader("authorization", "Bearer " + MpesaConfig.AccessToken).addHeader("cache-control", "no-cache").build(); Response response = client.newCall(request).execute(); String info = response.body().string(); logger.info("pay request end; info:" + info); return info; } /** * 查詢在線訂單狀態 * * @param checkoutRequestID * 在線付款提交成功後返回 checkoutRequestID * @return * @throws IOException */ public static String STKPushTransactionStatus(String checkoutRequestID) throws IOException { logger.info(String.format("pay status begin; checkoutRequestID:%s", checkoutRequestID)); if (MpesaConfig.AccessToken == null) { MpesaConfig.AccessToken = authenticate(); } String timestamp = MpesaUtils.getTimestamp(); String password = MpesaUtils.getPassword(MpesaConfig.BUSINESS_SHORT_CODE, MpesaConfig.PASSKEY, timestamp); STKPushTransactionStatusBean bean = new STKPushTransactionStatusBean(MpesaConfig.BUSINESS_SHORT_CODE, password, timestamp, checkoutRequestID); Gson gson = new Gson(); String requestJson = gson.toJson(bean); OkHttpClient client = new OkHttpClient(); MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, requestJson); Request request = new Request.Builder().url(MpesaConfig.BASE_URL + "/mpesa/stkpushquery/v1/query").post(body) .addHeader("authorization", "Bearer " + MpesaConfig.AccessToken).addHeader("content-type", "application/json") .build(); Response response = client.newCall(request).execute(); String info = response.body().string(); logger.info("pay status end; info:" + info); return info; } public String reversal(String initiator, String securityCredential, String commandID, String transactionID, String amount, String receiverParty, String recieverIdentifierType, String resultURL, String queueTimeOutURL, String remarks, String ocassion) throws IOException { if (MpesaConfig.AccessToken == null) { MpesaConfig.AccessToken = authenticate(); } JSONArray jsonArray = new JSONArray(); JSONObject jsonObject = new JSONObject(); try { jsonObject.put("Initiator", initiator); jsonObject.put("SecurityCredential", securityCredential); jsonObject.put("CommandID", commandID); jsonObject.put("TransactionID", transactionID); jsonObject.put("Amount", amount); jsonObject.put("ReceiverParty", receiverParty); jsonObject.put("RecieverIdentifierType", recieverIdentifierType); jsonObject.put("QueueTimeOutURL", queueTimeOutURL); jsonObject.put("ResultURL", resultURL); jsonObject.put("Remarks", remarks); jsonObject.put("Occasion", ocassion); } catch (JSONException e) { e.printStackTrace(); } jsonArray.add(jsonObject); String requestJson = jsonArray.toString().replaceAll("[\\[\\]]", ""); logger.info("reversal requestJson:" + requestJson); OkHttpClient client = new OkHttpClient(); MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, requestJson); Request request = new Request.Builder().url(MpesaConfig.BASE_URL + "/safaricom/reversal/v1/request").post(body) .addHeader("content-type", "application/json") .addHeader("authorization", "Bearer xNA3e9KhKQ8qkdTxJJo7IDGkpFNV") .addHeader("cache-control", "no-cache").build(); Response response = client.newCall(request).execute(); String info = response.body().string(); logger.info("reversal end; info:" + info); return info; } public String balanceInquiry(String initiator, String commandID, String securityCredential, String partyA, String identifierType, String remarks, String queueTimeOutURL, String resultURL) throws IOException { if (MpesaConfig.AccessToken == null) { MpesaConfig.AccessToken = authenticate(); } JSONArray jsonArray = new JSONArray(); JSONObject jsonObject = new JSONObject(); try { jsonObject.put("Initiator", initiator); jsonObject.put("SecurityCredential", securityCredential); jsonObject.put("CommandID", commandID); jsonObject.put("PartyA", partyA); jsonObject.put("IdentifierType", identifierType); jsonObject.put("Remarks", remarks); jsonObject.put("QueueTimeOutURL", queueTimeOutURL); jsonObject.put("ResultURL", resultURL); } catch (JSONException e) { e.printStackTrace(); } jsonArray.add(jsonObject); String requestJson = jsonArray.toString().replaceAll("[\\[\\]]", ""); logger.info("balanceInquiry requestJson:" + requestJson); OkHttpClient client = new OkHttpClient(); MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, requestJson); Request request = new Request.Builder().url(MpesaConfig.BASE_URL + "/safaricom/accountbalance/v1/query") .post(body).addHeader("content-type", "application/json") .addHeader("authorization", "Bearer fwu89P2Jf6MB1A2VJoouPg0BFHFM") .addHeader("cache-control", "no-cache") .addHeader("postman-token", "2aa448be-7d56-a796-065f-b378ede8b136").build(); Response response = client.newCall(request).execute(); String info = response.body().string(); logger.info("balanceInquiry end; info:" + info); return info; } public String registerURL(String shortCode, String responseType, String confirmationURL, String validationURL) throws IOException { if (MpesaConfig.AccessToken == null) { MpesaConfig.AccessToken = authenticate(); } JSONArray jsonArray = new JSONArray(); JSONObject jsonObject = new JSONObject(); try { jsonObject.put("ShortCode", shortCode); jsonObject.put("ResponseType", responseType); jsonObject.put("ConfirmationURL", confirmationURL); jsonObject.put("ValidationURL", validationURL); } catch (JSONException e) { e.printStackTrace(); } jsonArray.add(jsonObject); String requestJson = jsonArray.toString().replaceAll("[\\[\\]]", ""); logger.info("registerURL requestJson:" + requestJson); OkHttpClient client = new OkHttpClient(); MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, requestJson); Request request = new Request.Builder().url(MpesaConfig.BASE_URL + "/mpesa/c2b/v1/registerurl").post(body) .addHeader("content-type", "application/json").addHeader("authorization", "Bearer " + MpesaConfig.AccessToken) .addHeader("cache-control", "no-cache").build(); Response response = client.newCall(request).execute(); String info = response.body().string(); logger.info("registerURL end; info:" + info); return info; } }
MpesaUtils:
package com.mpesa; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import org.apache.tomcat.util.codec.binary.Base64; /** * Created by miles on 23/11/2017. * Taken from https://github.com/bdhobare/mpesa-android-sdk */ public class MpesaUtils { public static String getTimestamp() { return new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).format(new Date()); } public static String sanitizePhoneNumber(String phone) { if (phone.equals("")) { return ""; } if (phone.length() < 11 & phone.startsWith("0")) { String p = phone.replaceFirst("^0", "254"); return p; } if (phone.length() == 13 && phone.startsWith("+")) { String p = phone.replaceFirst("^+", ""); return p; } return phone; } public static String getPassword(String businessShortCode, String passkey, String timestamp) { String str = businessShortCode + passkey + timestamp; //encode the password to Base64 // return Base64.encodeToString(str.getBytes(), Base64.NO_WRAP); return Base64.encodeBase64String(str.getBytes()); } }
STKPush
package com.mpesa; /** * 在線付款請求參數 * */ public class STKPush { /* { "BusinessShortCode": "", "Password": "", "Timestamp": "", "TransactionType": "CustomerPayBillOnline", "Amount": "", "PartyA": "", "PartyB": "", "PhoneNumber": "", "CallBackURL": "", "AccountReference": "", "TransactionDesc": "" } */ //收款方短碼 組織短代碼 private String BusinessShortCode; // 在線支付密碼 base64.encode(Shortcode + Passkey + Timestamp),passkey爲在線支付密碼 private String Password; //時間戳 YYYYMMDDHHmmss private String Timestamp; // 付款類型 CustomerPayBillOnline(默認) CustomerBuyGoodsOnline private String TransactionType; // 金額 整數 private String Amount; // 寄錢電話號碼 付款方 private String PartyA; // 收款方 ,與businessShortCode 相同 private String PartyB; // 付款號碼 2547*** 12位 用於接收STK推送,與PartA 相同 private String PhoneNumber; // 付款請求發送成功,mpesa服務器 發送消息付款推送到客戶手機成功後,調用此連接 通知用戶(本身服務器) private String CallBackURL; //帳戶備註 小於12個字符(字母和數字的任何組合) private String AccountReference; // 其餘信息 小於13 字符, private String TransactionDesc; public STKPush(String businessShortCode, String password, String timestamp, String transactionType, String amount, String partyA, String partyB, String phoneNumber, String callBackURL, String accountReference, String transactionDesc) { this.BusinessShortCode = businessShortCode; this.Password = password; this.Timestamp = timestamp; this.TransactionType = transactionType; this.Amount = amount; this.PartyA = partyA; this.PartyB = partyB; this.PhoneNumber = phoneNumber; this.CallBackURL = callBackURL; this.AccountReference = accountReference; this.TransactionDesc = transactionDesc; } }
STKPushTransactionStatusBean
package com.mpesa; /** * 在線付款查詢請求倉庫 * @author zzc * */ public class STKPushTransactionStatusBean { /*{ "BusinessShortCode": " " , 收款方斷代碼 "Password": " ", 密鑰 "Timestamp": " ", 時間戳 "CheckoutRequestID": " " 在線付款id }*/ private String BusinessShortCode; private String Password; private String Timestamp; private String CheckoutRequestID; public String getBusinessShortCode() { return BusinessShortCode; } public void setBusinessShortCode(String businessShortCode) { BusinessShortCode = businessShortCode; } public String getPassword() { return Password; } public void setPassword(String password) { Password = password; } public String getTimestamp() { return Timestamp; } public void setTimestamp(String timestamp) { Timestamp = timestamp; } public String getCheckoutRequestID() { return CheckoutRequestID; } public void setCheckoutRequestID(String checkoutRequestID) { CheckoutRequestID = checkoutRequestID; } public STKPushTransactionStatusBean(String businessShortCode, String password, String timestamp, String checkoutRequestID) { BusinessShortCode = businessShortCode; Password = password; Timestamp = timestamp; CheckoutRequestID = checkoutRequestID; } }