# 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"

### 二、使用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)。

認證成功導向回指定的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 小額