# Hinet小額付費API ## 更新紀錄 * 2020/11/22 更新版本:20.11.11-SNAPSHOT * 2020/11/22 加入HttpClient Timeout設定 * 2020/11/16 更新版本:20.11.6-SNAPSHOT * 2020/11/16 防止啟動失敗 * 2020/11/06 更新版本:20.10.11-SNAPSHOT * 2020/11/06 判斷HiTOPS帳號不能使用於正式區(HiTOPS43除外)。 ## 使用說明 ### 一、設定 1. 使用common-api-fwk: 20.10.10 ``` <dependency> <groupId>geps3</groupId> <artifactId>common-api-fwk</artifactId> <version>20.10.10-SNAPSHOT</version> </dependency> ``` 2. WebConfig.java加上"geps3.pms.qdcs.common" ![](https://i.imgur.com/P7fILVv.jpg) ### 二、使用HinetAAAClient ``` @Autowired private HinetAAAClient aaaClient; ``` ### 三、一般小額付費流程(1A->2A->3A) > **領標較為複雜將於第四節另外敘述流程** #### 1A認證(Authentic) 1.傳入產品代碼、網址、費用產生1A認證參數(AaaAuthenticRq),組成HTML form送出,將使用者網頁導向小額付費網站進行認證。 ``` AaaAuthenticRq authenticRq = aaaClient.getAuthenticRequest(productId, curl, eurl, fee); request.setAttribute("aaRequestURL", authenticRq.getRequestURL()); // 小額支付認證介面網址 request.setAttribute("aaVersion", authenticRq.getVersion()); // 系統版本 request.setAttribute("aaProductId", authenticRq.getProductId()); request.setAttribute("aaCurl", authenticRq.getCurl()); request.setAttribute("aaEurl", authenticRq.getEurl()); request.setAttribute("aaFee", authenticRq.getFee()); request.setAttribute("aaOthers", authenticRq.getOthers()); // 廠商自訂參數(目前均設為"others") request.setAttribute("aaSum", authenticRq.getSum()); // MD5驗證碼 ... ``` > productId:產品代碼(領標288983、報價289013...)。 > curl:認證成功後返回網址,如: http://myhost/qdcs/paySuccess。 > eurl:認證失敗時返回網址。 > fee:產品費用。 ``` JSP: <form method="post" action="${aaRequestURL}" id="a1PaymentForm"> <input type="hidden" name="aa-version" value="${aaVersion}"> <input type="hidden" name="aa-productid" value="${aaProductId}"> <input type="hidden" name="aa-curl" value="${aaCurl}"> <input type="hidden" name="aa-eurl" value="${aaEurl}"> <input type="hidden" name="aa-fee" value="${aaFee}"> <input type="hidden" name="aa-others" value="${aaOthers}"> <input type="hidden" name="aa-sum" value="${aaSum}"> </form> ``` 網頁送出後導向中華支付,使用者輸入帳號密碼認證>送出後導回指定的Curl(錯誤則為Eurl)。 ![](https://i.imgur.com/anKLkGU.png) 認證成功導向回指定的curl後,要繼續進行2A授權。 #### 2A授權(Authorize) Controller接收支付成功導回的訊息,解析回傳的訊息。 ``` @RequestMapping("/paySuccess") public paySuccess() { String productId = "289013"; AaaAuthenticRs authenticRs = aaaClient.parseAuthenticRs(request); if (authenticRs.isSuccess()) { // 認證成功 String otpw = authenticRs.getOtpw(); ... } ... } ``` 確認認證成功,可取得認證授權碼otpw,以此授權碼進行2A授權。 ``` AaaAuthAcctRs authorizeRs = aaaClient.sendAuthorizeRq(authenticRs.getOtpw(), authenticRs.getFee(), authenticRs.getAuthority(), productId); if (authorizeRs.isSuccess) { // 授權成功 ... } ``` #### 3A扣款(Account) 2A授權成功後,最後進行3A扣款(**此步驟完成才算真正付費扣款成功**)。 ``` String serviceRemark = model.getTenderOrgId() + "_000" + "^" + model.getTenderCaseNo() + "^" + model.getTenderSq() + "^00^" + tokenNo + "^" + getUserIp(); AaaAuthAcctRs accountingRs = aaaClient .sendAccountingRq(authenticRs.getOtpw(), authenticRs.getFee(), authenticRs.getAuthority(), stime, serviceRemark, productId); if (accountingRs.isSuccess()) { // 至此小額支付扣款成功,可進行付款資料儲存紀錄 service.saveEqmToken(eqmToken); } ``` > stime:當前消費(啟始)時間(yyyyMMddHHmmss)。 > serviceRemark:服務備註,使用者自訂用來識別服務的資訊,建議用^分隔。 #### 取得帳號餘額(RemainQuota) 如需取得使用之帳號餘額 ``` AaaRemainQuotaRs remainQuota = aaaClient.getRemainQuota(authenticRs.getUid(), authenticRs.getHn(), productId); if(remainQuota.isSuccess()) { String quota = remainQuota.getRemainingQuota(); // 如:"9999.00" ... } ``` > uid、hn為1A返回之參數取得,兩者可擇一輸入,如都有輸入則以uid為優先。 ### 四、電子領標付費流程 電子領標由於有三個產品代碼,付款流程如下: 1. 1A以產品代碼288983(正式、練習相同這組)產生認證參數,然後導向支付網頁。 ``` AaaAuthenticRq authenticRq = aaaClient.getAuthenticRequest("288983", curl, eurl, fee); ``` > fee:這邊的費用等於招標設定(TPAM_TENDER_MAIN)的系統使用費(SYSTEM_CHARGE)+招標文件費(DEPT_CHARGE)+文件代收費(DOC_CHARGE) 2. 認證成功後導回Controller,取得認證授權碼(otpw),接著進行各項產品授權,先以1A的產品代碼及費用呼叫2A確認授權成功。 ``` AaaAuthAcctRs authorizeRs = aaaClient.sendAuthorizeRq(authenticRs.getOtpw(), authenticRs.getFee(), authenticRs.getAuthority(), "288983"); ``` > 經測試費用比照二代傳0也可以 3. 接著判斷招標設定的三項費用,如果有收取,則以該項產品代碼及費用先進行交換授權碼(APA1),再進行2A授權。 ``` List<AaaAuthAcctRs> authAcctList = new ArrayList<>(); if (tpam.systemCharge>0) { AaaExchangeOtpwRs xchgOtpwRs = aaaClient.sendAPA1Rq(authenticRs.getOtpw(), tpam.systemCharge, authenticRs.getAuthority(), sysProductId); if (!xchgOtpwRs.isSuccess()) { throw new Exception("..."); } String newOtpw = xchgOtpwRs.getNewOtpw(); AaaAuthAcctRs authorizeSys = aaaClient.sendAuthorizeRq(newOtpw, tpam.systemCharge, authenticRs.getAuthority(), sysProductId); authAcctList.add(authorizeSys); } if (tpam.deptCharge>0) { AaaAuthAcctRs authorizeDept = aaaClient.sendAuthorizeRq(authenticRs.getOtpw(), tpam.deptCharge, authenticRs.getAuthority(), deptProductId); authAcctList.add(authorizeDept); } if (tpam.docCharge>0) { AaaAuthAcctRs authorizeDoc = aaaClient.sendAuthorizeRq(authenticRs.getOtpw(), tpam.docCharge, authenticRs.getAuthority(), docProductId); authAcctList.add(authorizeDoc); } ``` > ProductId:系統使用費288990/288984(練習區)、招標文件費288991/288987(練習區)、文件代收費288992/288988(練習區)。 4. 2A授權成功後,同樣分別進行3A扣款(參考上述3A扣款)。 ``` String tokenNo = service.createToken(); for (AaaAuthAcctRs authAcct: authAcctList) { AaaAuthAcctRs accountingRs = aaaClient .sendAccountingRq(authenticRs.getOtpw(), fee, authenticRs.getAuthority(), stime, serviceRemark, productId); if(!accountingRs.isSuccess()) { service.deleteToken(tokenNo); ... break; } } ``` > otpw、authority均為1A時取得;fee、productId則為2A根據費用類型有所不同 > 領標時,各項費用3A扣款如有某次失敗則**視為失敗**,需刪除系統已記錄之領標憑據。 5. 根據已經產生之憑據,可提供使用者下載憑據檔案與其他相關作業。 ###### tags: GEPS3 AAA 小額