公交二维码对接接口
diff --git a/build.gradle b/build.gradle
index 4cbb0ed..1d0b788 100644
--- a/build.gradle
+++ b/build.gradle
@@ -56,7 +56,7 @@
compile group: 'org.apache.poi', name: 'poi-ooxml', version: '3.10.1'
compile group: 'org.apache.poi', name: 'poi-ooxml-schemas', version: '3.10.1'
compile group: 'org.apache.poi', name: 'poi-scratchpad', version: '3.10.1'
- compile 'com.supwisdom:payapi-sdk:1.0.11'
+ compile 'com.supwisdom:payapi-sdk:1.0.28-2-g03919bd.dirty'
compile group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version: '2.3.4.RELEASE'
diff --git a/config/application-devel-pg.properties b/config/application-devel-pg.properties
index 9342bff..2f72996 100644
--- a/config/application-devel-pg.properties
+++ b/config/application-devel-pg.properties
@@ -4,8 +4,8 @@
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
spring.datasource.continue-on-error=true
#spring.datasource.initialization-mode=always
-spring.jpa.show-sql=true
-logging.level.org.hibernate.SQL=DEBUG
+spring.jpa.show-sql=false
+logging.level.org.hibernate.SQL=ERROR
# Postgresql settings
spring.datasource.platform=postgresql
spring.datasource.url=jdbc:postgresql://172.28.201.70:15432/restauranttest
@@ -25,12 +25,21 @@
spring.jackson.serialization.fail-on-empty-beans=false
-payapi.url=http://172.28.201.70:10010/payapi
+#payapi.url=http://172.28.201.70:10010/payapi
+payapi.url=http://localhost:8080/payapi
payapi.appid=200001
+payapi.logintime= 0 0/5 * * * ?
cron.offlinedtl= 0 0/5 * * * ?
-payapi.logintime= 0 0/5 * * * ?
-busapp.cardsync.cron=0 0/1 * * * ?
+#busapp.cardsync.cron=0 0/1 * * * ?
+busapp.cardsync.cron=-
payapi.submitOfflineDtl=-
-payapi.checkWipDtl=-
\ No newline at end of file
+payapi.checkWipDtl=-
+busapp.upload.transdtl.task.cron=0 0/1 * * * ?
+
+#restaurant.sync.card.task.cron=0 0/1 * * * ?
+restaurant.sync.card.task.cron=-
+restaurant.chkdtltask.cron=-
+
+server.servlet.context-path=/carbus
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/BusApiResp.java b/src/main/java/com/supwisdom/dlpay/bus/bean/BusApiResp.java
index 4956990..82f3d09 100644
--- a/src/main/java/com/supwisdom/dlpay/bus/bean/BusApiResp.java
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/BusApiResp.java
@@ -4,6 +4,14 @@
private String retcode;
private String retmsg;
+ public BusApiResp() {
+ }
+
+ public BusApiResp(String retcode, String retmsg) {
+ this.retcode = retcode;
+ this.retmsg = retmsg;
+ }
+
public String getRetcode() {
return retcode;
}
@@ -20,6 +28,15 @@
this.retmsg = retmsg;
}
+ public void error(String retcode, String retmsg) {
+ this.retcode = retcode;
+ this.retmsg = retmsg;
+ }
+
+ public String errmsg() {
+ return "retcode=[" + retcode + "],retmsg=[" + retmsg + "]";
+ }
+
@Override
public String toString() {
return "retcode=[" + retcode + "],retmsg=[" + retmsg + "]";
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeBaseReq.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeBaseReq.java
new file mode 100644
index 0000000..b9ff163
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeBaseReq.java
@@ -0,0 +1,138 @@
+package com.supwisdom.dlpay.bus.bean;
+
+import com.supwisdom.dlpay.bus.util.ReqErrorException;
+import com.supwisdom.dlpay.framework.util.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.beans.Introspector;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class QrcodeBaseReq {
+ @Sign
+ private String partner_id;
+ @Sign
+ private String timestamp;
+ @Sign
+ private String sign;
+ @Sign
+ private String sign_method;
+ @Sign
+ private String version;
+
+ private static final Logger logger = LoggerFactory.getLogger(APIRequestParam.class);
+
+ public String getPartner_id() {
+ return partner_id;
+ }
+
+ public void setPartner_id(String partner_id) {
+ this.partner_id = partner_id;
+ }
+
+ public String getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(String timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public String getSign() {
+ return sign;
+ }
+
+ public void setSign(String sign) {
+ this.sign = sign;
+ }
+
+ public String getSign_method() {
+ return sign_method;
+ }
+
+ public void setSign_method(String sign_method) {
+ this.sign_method = sign_method;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ private boolean calcSignAndCheck(Map<String, String> map, String key) {
+ String sign = map.get("sign");
+ String signType = map.get("sign_method");
+ if (StringUtil.isEmpty(sign)) return false;
+
+ String signdata = StringUtil.createLinkString(StringUtil.swParaFilter(map)); //除了sign所有的非空(null或"")都要参与签名
+ logger.info("signdata=[" + signdata + "]");
+
+ String calcSign = null;
+ if ("HMAC".equalsIgnoreCase(signType)) {
+ calcSign = HmacUtil.HMACSHA1(signdata, key);
+ } else if ("MD5".equalsIgnoreCase(signType)) {
+ calcSign = MD5.encodeByMD5(signdata + key);
+ }
+
+ if (sign.equalsIgnoreCase(calcSign)) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean checkSign(String key) {
+ Class clazz = this.getClass();
+ Map<String, String> paramMap = new HashMap<>();
+ Method[] allGetter = clazz.getMethods();
+
+ for (Method meth : allGetter) {
+ if (meth.getName().startsWith("get") || meth.getName().startsWith("is")) {
+ String fieldName = Introspector.decapitalize(meth.getName().substring(meth.getName().startsWith("get") ? 3 : 2));
+ Field field;
+ try {
+ field = clazz.getDeclaredField(fieldName);
+ } catch (NoSuchFieldException e) {
+ try {
+ field = clazz.getSuperclass().getDeclaredField(fieldName);
+ } catch (NoSuchFieldException e1) {
+ continue;
+ }
+ }
+
+ if (field.isAnnotationPresent(Sign.class)) {
+ Object value;
+ try {
+ value = meth.invoke(this);
+ } catch (Exception e) {
+ e.printStackTrace();
+ continue;
+ }
+ paramMap.put(fieldName, value == null ? null : value.toString());
+ }
+ }
+ }
+ return calcSignAndCheck(paramMap, key);
+ }
+
+ public abstract boolean checkParam() throws ReqErrorException;
+
+ public boolean baseCheck() throws ReqErrorException {
+ if (StringUtil.isEmpty(this.partner_id)) throw new ReqErrorException("请求参数错误[合作伙伴ID为空]");
+ if (!DateUtil.checkDatetimeValid(timestamp, "yyyyMMddHHmmss")) throw new ReqErrorException("请求参数错误[时间戳格式错误]");
+ final String nowTime = DateUtil.getNow("yyyyMMddHHmmss");
+ if (DateUtil.compareDatetime(nowTime, this.timestamp, -600) > 0 || DateUtil.compareDatetime(nowTime, this.timestamp, 600) < 0)
+ throw new ReqErrorException("请求参数错误[时间戳误差10分钟以上]");
+
+ if (StringUtil.isEmpty(sign)) throw new ReqErrorException("请求参数错误[签名为空]");
+ if (!Arrays.asList("HMAC", "MD5").contains(sign_method)) throw new ReqErrorException("请求参数错误[签名方法错误]");
+ if (StringUtil.isEmpty(this.version)) throw new ReqErrorException("请求参数错误[版本号为空]");
+ return true;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeKeysReq.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeKeysReq.java
new file mode 100644
index 0000000..fc20a25
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeKeysReq.java
@@ -0,0 +1,10 @@
+package com.supwisdom.dlpay.bus.bean;
+
+import com.supwisdom.dlpay.bus.util.ReqErrorException;
+
+public class QrcodeKeysReq extends QrcodeBaseReq {
+ @Override
+ public boolean checkParam() throws ReqErrorException {
+ return super.baseCheck();
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeKeysResp.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeKeysResp.java
new file mode 100644
index 0000000..d64b0b5
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeKeysResp.java
@@ -0,0 +1,13 @@
+package com.supwisdom.dlpay.bus.bean;
+
+public class QrcodeKeysResp extends BusApiResp {
+ private String key;
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayCancelReq.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayCancelReq.java
new file mode 100644
index 0000000..14d6f99
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayCancelReq.java
@@ -0,0 +1,46 @@
+package com.supwisdom.dlpay.bus.bean;
+
+import com.supwisdom.dlpay.bus.util.ReqErrorException;
+import com.supwisdom.dlpay.framework.util.Sign;
+import com.supwisdom.dlpay.framework.util.StringUtil;
+
+public class QrcodePayCancelReq extends QrcodeBaseReq {
+ @Sign
+ private String billno;
+ @Sign
+ private String refno;
+ @Sign
+ private String cancelBillno;
+
+ public String getBillno() {
+ return billno;
+ }
+
+ public void setBillno(String billno) {
+ this.billno = billno;
+ }
+
+ public String getRefno() {
+ return refno;
+ }
+
+ public void setRefno(String refno) {
+ this.refno = refno;
+ }
+
+ public String getCancelBillno() {
+ return cancelBillno;
+ }
+
+ public void setCancelBillno(String cancelBillno) {
+ this.cancelBillno = cancelBillno;
+ }
+
+ @Override
+ public boolean checkParam() throws ReqErrorException {
+ super.baseCheck();
+ if (StringUtil.isEmpty(refno) && StringUtil.isEmpty(billno)) throw new ReqErrorException("请求参数错误[原始订单号不能都为空]");
+ if (StringUtil.isEmpty(cancelBillno)) throw new ReqErrorException("请求参数错误[撤销的商户订单号不能为空]");
+ return true;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayCancelResp.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayCancelResp.java
new file mode 100644
index 0000000..5d5eb78
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayCancelResp.java
@@ -0,0 +1,13 @@
+package com.supwisdom.dlpay.bus.bean;
+
+public class QrcodePayCancelResp extends BusApiResp {
+ private String refno;
+
+ public String getRefno() {
+ return refno;
+ }
+
+ public void setRefno(String refno) {
+ this.refno = refno;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayConfirmReq.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayConfirmReq.java
new file mode 100644
index 0000000..9561ddf
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayConfirmReq.java
@@ -0,0 +1,35 @@
+package com.supwisdom.dlpay.bus.bean;
+
+import com.supwisdom.dlpay.bus.util.ReqErrorException;
+import com.supwisdom.dlpay.framework.util.Sign;
+import com.supwisdom.dlpay.framework.util.StringUtil;
+
+public class QrcodePayConfirmReq extends QrcodeBaseReq {
+ @Sign
+ private String billno;
+ @Sign
+ private String refno;
+
+ public String getBillno() {
+ return billno;
+ }
+
+ public void setBillno(String billno) {
+ this.billno = billno;
+ }
+
+ public String getRefno() {
+ return refno;
+ }
+
+ public void setRefno(String refno) {
+ this.refno = refno;
+ }
+
+ @Override
+ public boolean checkParam() throws ReqErrorException {
+ super.baseCheck();
+ if (StringUtil.isEmpty(refno) && StringUtil.isEmpty(billno)) throw new ReqErrorException("请求参数错误[流水号不能都为空]");
+ return true;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayInitReq.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayInitReq.java
new file mode 100644
index 0000000..3b6e8c2
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayInitReq.java
@@ -0,0 +1,101 @@
+package com.supwisdom.dlpay.bus.bean;
+
+import com.supwisdom.dlpay.bus.util.ReqErrorException;
+import com.supwisdom.dlpay.framework.util.DateUtil;
+import com.supwisdom.dlpay.framework.util.Sign;
+import com.supwisdom.dlpay.framework.util.StringUtil;
+
+public class QrcodePayInitReq extends QrcodeBaseReq {
+ @Sign
+ private String qrcode; //二维码
+ @Sign
+ private String billno; //商户订单号
+ @Sign
+ private Long amount; //交易金额
+ @Sign
+ private String transDate; //交易日期 yyyyMMdd
+ @Sign
+ private String transTime; //交易时间
+ @Sign
+ private String termdesc; //终端描述,可空
+ @Sign
+ private String cardNo; //市民卡号,可空
+ @Sign
+ private String tac; //二维码计算的流水tac,可空
+
+ @Override
+ public boolean checkParam() throws ReqErrorException {
+ super.baseCheck();
+ if (StringUtil.isEmpty(this.qrcode)) throw new ReqErrorException("请求参数错误[二维码为空]");
+ if (StringUtil.isEmpty(this.billno)) throw new ReqErrorException("请求参数错误[商户订单号为空]");
+ if (null == this.amount || this.amount <= 0) throw new ReqErrorException("请求参数错误[交易金额必须大于0]");
+ if (!DateUtil.checkDatetimeValid(this.transDate, "yyyyMMdd")) throw new ReqErrorException("请求参数错误[交易日期格式错误]");
+ if (!DateUtil.checkDatetimeValid(this.transDate + this.transTime, "yyyyMMddHHmmss"))
+ throw new ReqErrorException("请求参数错误[交易时间格式错误]");
+ return true;
+ }
+
+ public String getQrcode() {
+ return qrcode;
+ }
+
+ public void setQrcode(String qrcode) {
+ this.qrcode = qrcode;
+ }
+
+ public String getCardNo() {
+ return cardNo;
+ }
+
+ public void setCardNo(String cardNo) {
+ this.cardNo = cardNo;
+ }
+
+ public String getBillno() {
+ return billno;
+ }
+
+ public void setBillno(String billno) {
+ this.billno = billno;
+ }
+
+ public Long getAmount() {
+ return amount;
+ }
+
+ public void setAmount(Long amount) {
+ this.amount = amount;
+ }
+
+ public String getTransDate() {
+ return transDate;
+ }
+
+ public void setTransDate(String transDate) {
+ this.transDate = transDate;
+ }
+
+ public String getTransTime() {
+ return transTime;
+ }
+
+ public void setTransTime(String transTime) {
+ this.transTime = transTime;
+ }
+
+ public String getTac() {
+ return tac;
+ }
+
+ public void setTac(String tac) {
+ this.tac = tac;
+ }
+
+ public String getTermdesc() {
+ return termdesc;
+ }
+
+ public void setTermdesc(String termdesc) {
+ this.termdesc = termdesc;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayResp.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayResp.java
new file mode 100644
index 0000000..0dee18a
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodePayResp.java
@@ -0,0 +1,31 @@
+package com.supwisdom.dlpay.bus.bean;
+
+public class QrcodePayResp extends BusApiResp {
+ private String refno;
+ private String billno;
+ private Integer amount;
+
+ public String getRefno() {
+ return refno;
+ }
+
+ public void setRefno(String refno) {
+ this.refno = refno;
+ }
+
+ public String getBillno() {
+ return billno;
+ }
+
+ public void setBillno(String billno) {
+ this.billno = billno;
+ }
+
+ public Integer getAmount() {
+ return amount;
+ }
+
+ public void setAmount(Integer amount) {
+ this.amount = amount;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeQueryReq.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeQueryReq.java
new file mode 100644
index 0000000..d3deca6
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeQueryReq.java
@@ -0,0 +1,36 @@
+package com.supwisdom.dlpay.bus.bean;
+
+import com.supwisdom.dlpay.bus.util.ReqErrorException;
+import com.supwisdom.dlpay.framework.util.Sign;
+import com.supwisdom.dlpay.framework.util.StringUtil;
+
+public class QrcodeQueryReq extends QrcodeBaseReq {
+ @Sign
+ private String uid;
+ @Sign
+ private String userid;
+
+ public String getUid() {
+ return uid;
+ }
+
+ public void setUid(String uid) {
+ this.uid = uid;
+ }
+
+ public String getUserid() {
+ return userid;
+ }
+
+ public void setUserid(String userid) {
+ this.userid = userid;
+ }
+
+ @Override
+ public boolean checkParam() throws ReqErrorException {
+ super.baseCheck();
+ if(StringUtil.isEmpty(uid)) throw new ReqErrorException("请求参数错误[手机唯一号不能为空]");
+ if(StringUtil.isEmpty(userid)) throw new ReqErrorException("请求参数错误[用户唯一号不能为空]");
+ return true;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeQueryResp.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeQueryResp.java
new file mode 100644
index 0000000..9309f5e
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeQueryResp.java
@@ -0,0 +1,13 @@
+package com.supwisdom.dlpay.bus.bean;
+
+public class QrcodeQueryResp extends BusApiResp{
+ private String qrcode;
+
+ public String getQrcode() {
+ return qrcode;
+ }
+
+ public void setQrcode(String qrcode) {
+ this.qrcode = qrcode;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeQueryResultReq.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeQueryResultReq.java
new file mode 100644
index 0000000..756390d
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeQueryResultReq.java
@@ -0,0 +1,35 @@
+package com.supwisdom.dlpay.bus.bean;
+
+import com.supwisdom.dlpay.bus.util.ReqErrorException;
+import com.supwisdom.dlpay.framework.util.Sign;
+import com.supwisdom.dlpay.framework.util.StringUtil;
+
+public class QrcodeQueryResultReq extends QrcodeBaseReq {
+ @Sign
+ private String billno;
+ @Sign
+ private String refno;
+
+ public String getBillno() {
+ return billno;
+ }
+
+ public void setBillno(String billno) {
+ this.billno = billno;
+ }
+
+ public String getRefno() {
+ return refno;
+ }
+
+ public void setRefno(String refno) {
+ this.refno = refno;
+ }
+
+ @Override
+ public boolean checkParam() throws ReqErrorException {
+ super.baseCheck();
+ if (StringUtil.isEmpty(refno) && StringUtil.isEmpty(billno)) throw new ReqErrorException("请求参数错误[流水号不能都为空]");
+ return true;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeQueryResultResp.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeQueryResultResp.java
new file mode 100644
index 0000000..e63e969
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeQueryResultResp.java
@@ -0,0 +1,94 @@
+package com.supwisdom.dlpay.bus.bean;
+
+public class QrcodeQueryResultResp extends BusApiResp {
+ private String billno;
+ private String refno;
+ private Integer amount;
+ private String status;
+ private String cardno;
+ private String sourceType;
+ private String reverseFlag;
+ private String transdesc;
+ private String termdesc;
+ private String remark;
+
+ public String getBillno() {
+ return billno;
+ }
+
+ public void setBillno(String billno) {
+ this.billno = billno;
+ }
+
+ public String getRefno() {
+ return refno;
+ }
+
+ public void setRefno(String refno) {
+ this.refno = refno;
+ }
+
+ public Integer getAmount() {
+ return amount;
+ }
+
+ public void setAmount(Integer amount) {
+ this.amount = amount;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getCardno() {
+ return cardno;
+ }
+
+ public void setCardno(String cardno) {
+ this.cardno = cardno;
+ }
+
+ public String getSourceType() {
+ return sourceType;
+ }
+
+ public void setSourceType(String sourceType) {
+ this.sourceType = sourceType;
+ }
+
+ public String getReverseFlag() {
+ return reverseFlag;
+ }
+
+ public void setReverseFlag(String reverseFlag) {
+ this.reverseFlag = reverseFlag;
+ }
+
+ public String getTransdesc() {
+ return transdesc;
+ }
+
+ public void setTransdesc(String transdesc) {
+ this.transdesc = transdesc;
+ }
+
+ public String getTermdesc() {
+ return termdesc;
+ }
+
+ public void setTermdesc(String termdesc) {
+ this.termdesc = termdesc;
+ }
+
+ public String getRemark() {
+ return remark;
+ }
+
+ public void setRemark(String remark) {
+ this.remark = remark;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeStatementReq.java b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeStatementReq.java
new file mode 100644
index 0000000..5710713
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/bean/QrcodeStatementReq.java
@@ -0,0 +1,25 @@
+package com.supwisdom.dlpay.bus.bean;
+
+import com.supwisdom.dlpay.api.util.DateUtil;
+import com.supwisdom.dlpay.bus.util.ReqErrorException;
+import com.supwisdom.dlpay.framework.util.Sign;
+
+public class QrcodeStatementReq extends QrcodeBaseReq {
+ @Sign
+ private String checkDate;
+
+ public String getCheckDate() {
+ return checkDate;
+ }
+
+ public void setCheckDate(String checkDate) {
+ this.checkDate = checkDate;
+ }
+
+ @Override
+ public boolean checkParam() throws ReqErrorException {
+ super.baseCheck();
+ if (!DateUtil.checkDatetimeValid(checkDate, DateUtil.DATE_FMT)) throw new ReqErrorException("对账日期错误[yyyyMMdd]");
+ return true;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/controller/BusQrcodeConsumeController.java b/src/main/java/com/supwisdom/dlpay/bus/controller/BusQrcodeConsumeController.java
new file mode 100644
index 0000000..5aa017a
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/controller/BusQrcodeConsumeController.java
@@ -0,0 +1,378 @@
+package com.supwisdom.dlpay.bus.controller;
+
+import com.google.gson.Gson;
+import com.supwisdom.dlpay.bus.bean.*;
+import com.supwisdom.dlpay.bus.domain.TThirdpartQrcodeTransdtl;
+import com.supwisdom.dlpay.bus.service.QrcodeConsumeService;
+import com.supwisdom.dlpay.bus.util.BusConstant;
+import com.supwisdom.dlpay.bus.util.BusException;
+import com.supwisdom.dlpay.bus.util.ReqErrorException;
+import com.supwisdom.dlpay.bus.util.RespCode;
+import com.supwisdom.dlpay.framework.domain.TApiClient;
+import com.supwisdom.dlpay.framework.service.SystemUtilService;
+import com.supwisdom.dlpay.framework.util.StringUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 珠海益达乘车码消费接口
+ * 提供给第三方二维码相关接口
+ * 提供appId和appKey即可,无需获取jwt
+ */
+@RestController
+@RequestMapping("/api/thirdpay")
+public class BusQrcodeConsumeController {
+ @Autowired
+ private QrcodeConsumeService qrcodeConsumeService;
+ @Autowired
+ private SystemUtilService systemUtilService;
+
+ private static final Gson _gson = new Gson();
+ private static final Logger logger = LoggerFactory.getLogger(BusQrcodeConsumeController.class);
+
+ private void print(String url, BusApiResp resp) {
+ logger.error("url=[" + url + "]返回错误:" + resp.errmsg());
+ }
+
+ /**
+ * 获取二维码解码密钥
+ */
+ @PostMapping("/qrcode/keys")
+ public QrcodeKeysResp queryConfig(@ModelAttribute QrcodeKeysReq req) {
+ final String url = "/api/thirdpay/qrcode/keys";
+ QrcodeKeysResp resp = new QrcodeKeysResp();
+ try {
+ req.checkParam();
+ TApiClient apiClient = qrcodeConsumeService.getApiClientByAppId(req.getPartner_id());
+ if (null == apiClient) {
+ throw new ReqErrorException("请求参数错误[合作伙伴ID不存在]");
+ }
+
+ if (!req.checkSign(apiClient.getSecret())) {
+ resp.error(RespCode.SIGN_CHECK_ERROR, "签名错误");
+ print(url, resp);
+ return resp;
+ }
+
+ String key = qrcodeConsumeService.getPayapiQRCodeRootKey(apiClient.getSecret(), req.getTimestamp());
+ resp.setRetcode(RespCode.SUCCESS);
+ resp.setRetmsg("success");
+ resp.setKey(key);
+ logger.info("url=[" + url + "]成功返回:" + _gson.toJson(resp));
+ return resp;
+ } catch (ReqErrorException rex) {
+ resp.error(RespCode.REQ_PARAM_ERROR, rex.getMessage());
+ print(url, resp);
+ return resp;
+ } catch (BusException bex) {
+ resp.error(RespCode.BUSINESS_PROCESS_ERROR, bex.getMessage());
+ print(url, resp);
+ return resp;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ resp.error(RespCode.OTHER_ERROR, "system error!");
+ print(url, resp);
+ return resp;
+ }
+ }
+
+ /**
+ * 获取二维码
+ * */
+ @PostMapping("/qrcode")
+ public QrcodeQueryResp queryQrcode(@ModelAttribute QrcodeQueryReq req) {
+ final String url = "/api/thirdpay/qrcode";
+ QrcodeQueryResp resp = new QrcodeQueryResp();
+ try {
+ req.checkParam();
+ TApiClient apiClient = qrcodeConsumeService.getApiClientByAppId(req.getPartner_id());
+ if (null == apiClient) {
+ throw new ReqErrorException("请求参数错误[合作伙伴ID不存在]");
+ }
+
+ if (!req.checkSign(apiClient.getSecret())) {
+ resp.error(RespCode.SIGN_CHECK_ERROR, "签名错误");
+ print(url, resp);
+ return resp;
+ }
+
+ String data = qrcodeConsumeService.doQueryQRcode(req.getUid().trim(), req.getUserid().trim());
+ if(StringUtil.isEmpty(data)){
+ resp.error(RespCode.BUSINESS_PROCESS_ERROR, "获取二维码失败!");
+ print(url, resp);
+ return resp;
+ }
+
+ resp.setRetcode(RespCode.SUCCESS);
+ resp.setRetmsg("success");
+ resp.setQrcode(data);
+ logger.info("url=[" + url + "]成功返回:" + _gson.toJson(resp));
+ return resp;
+ } catch (ReqErrorException rex) {
+ resp.error(RespCode.REQ_PARAM_ERROR, rex.getMessage());
+ print(url, resp);
+ return resp;
+ } catch (BusException bex) {
+ resp.error(RespCode.BUSINESS_PROCESS_ERROR, bex.getMessage());
+ print(url, resp);
+ return resp;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ resp.error(RespCode.OTHER_ERROR, "system error!");
+ print(url, resp);
+ return resp;
+ }
+ }
+
+ /**
+ * 联机
+ * 二维码联机消费初始化,解码后会校验totp
+ */
+ @PostMapping("/qrcode/online/payInit")
+ public QrcodePayResp onlinePayInit(@ModelAttribute QrcodePayInitReq req) {
+ return payInit(false, req);
+ }
+
+ /**
+ * 脱机(脱机流水上传)
+ * 二维码脱机消费初始化,解码后不校验totp
+ */
+ @PostMapping("/qrcode/offline/payInit")
+ public QrcodePayResp offlinePayInit(@ModelAttribute QrcodePayInitReq req) {
+ return payInit(true, req);
+ }
+
+ private QrcodePayResp payInit(boolean offlineFlag, QrcodePayInitReq req) {
+ String url = offlineFlag ? "/api/thirdpay/qrcode/offline/payInit" : "/api/thirdpay/qrcode/online/payInit";
+ QrcodePayResp resp = new QrcodePayResp();
+ try {
+ req.checkParam();
+ if(offlineFlag){
+ //脱机二维码,要求设备解码后传cardNo和流水tac
+ if (StringUtil.isEmpty(req.getCardNo())) throw new ReqErrorException("请求参数错误[市民卡号为空]");
+ if (StringUtil.isEmpty(req.getTac())) throw new ReqErrorException("请求参数错误[流水TAC为空]");
+ }
+
+ TApiClient apiClient = qrcodeConsumeService.getApiClientByAppId(req.getPartner_id());
+ if (null == apiClient) {
+ throw new ReqErrorException("请求参数错误[合作伙伴ID不存在]");
+ }
+
+ if (!req.checkSign(apiClient.getSecret())) {
+ resp.error(RespCode.SIGN_CHECK_ERROR, "签名错误");
+ print(url, resp);
+ return resp;
+ }
+
+ String shopaccno = systemUtilService.getBusinessValue(BusConstant.QRCODE_THIRDPAY_SHOP_PREFIX + apiClient.getAppid().trim());
+ if (StringUtil.isEmpty(shopaccno)) {
+ resp.error(RespCode.SHOP_NOT_CONFIG, "收费商户未配置");
+ print(url, resp);
+ return resp;
+ }
+
+ TThirdpartQrcodeTransdtl transdtl = qrcodeConsumeService.saveQRcodeTransdtl(req.getPartner_id().trim(), req.getBillno().trim(),
+ req.getCardNo(), req.getAmount(), req.getTransDate(), req.getTransTime(), req.getQrcode(), req.getTac(), req.getTermdesc(), shopaccno.trim(), offlineFlag);
+
+ boolean ret = qrcodeConsumeService.doSendQRcodePayInit(transdtl, resp);
+ if (ret) {
+ logger.info("url=[" + url + "]成功返回:" + _gson.toJson(resp));
+ } else {
+ print(url, resp);
+ }
+ return resp;
+ } catch (ReqErrorException rex) {
+ resp.error(RespCode.REQ_PARAM_ERROR, rex.getMessage());
+ print(url, resp);
+ return resp;
+ } catch (BusException bex) {
+ resp.error(RespCode.BUSINESS_PROCESS_ERROR, bex.getMessage());
+ print(url, resp);
+ return resp;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ resp.error(RespCode.OTHER_ERROR, "system error!");
+ print(url, resp);
+ return resp;
+ }
+ }
+
+ /**
+ * 消费确认
+ */
+ @PostMapping("/payConfirm")
+ public QrcodePayResp payConfirm(@ModelAttribute QrcodePayConfirmReq req) {
+ String url = "/api/thirdpay/payConfirm";
+ QrcodePayResp resp = new QrcodePayResp();
+ try {
+ req.checkParam();
+ TApiClient apiClient = qrcodeConsumeService.getApiClientByAppId(req.getPartner_id());
+ if (null == apiClient) {
+ throw new ReqErrorException("请求参数错误[合作伙伴ID不存在]");
+ }
+
+ if (!req.checkSign(apiClient.getSecret())) {
+ resp.error(RespCode.SIGN_CHECK_ERROR, "签名错误");
+ print(url, resp);
+ return resp;
+ }
+
+ boolean ret = qrcodeConsumeService.doConfirmQRcodePay(req.getPartner_id().trim(), req.getRefno(), req.getBillno(), resp);
+ if (ret) {
+ logger.info("url=[" + url + "]成功返回:" + _gson.toJson(resp));
+ } else {
+ print(url, resp);
+ }
+ return resp;
+ } catch (ReqErrorException rex) {
+ resp.error(RespCode.REQ_PARAM_ERROR, rex.getMessage());
+ print(url, resp);
+ return resp;
+ } catch (BusException bex) {
+ resp.error(RespCode.BUSINESS_PROCESS_ERROR, bex.getMessage());
+ print(url, resp);
+ return resp;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ resp.error(RespCode.OTHER_ERROR, "system error!");
+ print(url, resp);
+ return resp;
+ }
+ }
+
+ /**
+ * 消费撤销
+ */
+ @PostMapping("/payCancel")
+ public QrcodePayCancelResp payCancel(@ModelAttribute QrcodePayCancelReq req) {
+ String url = "/api/thirdpay/payCancel";
+ QrcodePayCancelResp resp = new QrcodePayCancelResp();
+ try {
+ req.checkParam();
+ TApiClient apiClient = qrcodeConsumeService.getApiClientByAppId(req.getPartner_id());
+ if (null == apiClient) {
+ throw new ReqErrorException("请求参数错误[合作伙伴ID不存在]");
+ }
+
+ if (!req.checkSign(apiClient.getSecret())) {
+ resp.error(RespCode.SIGN_CHECK_ERROR, "签名错误");
+ print(url, resp);
+ return resp;
+ }
+
+ boolean ret = qrcodeConsumeService.doCancelQRcodeTransdtl(req.getPartner_id().trim(), req.getRefno(), req.getBillno(), req.getCancelBillno().trim(), resp);
+ if (ret) {
+ logger.info("url=[" + url + "]成功返回:" + _gson.toJson(resp));
+ } else {
+ print(url, resp);
+ }
+ return resp;
+ } catch (ReqErrorException rex) {
+ resp.error(RespCode.REQ_PARAM_ERROR, rex.getMessage());
+ print(url, resp);
+ return resp;
+ } catch (BusException bex) {
+ resp.error(RespCode.BUSINESS_PROCESS_ERROR, bex.getMessage());
+ print(url, resp);
+ return resp;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ resp.error(RespCode.OTHER_ERROR, "system error!");
+ print(url, resp);
+ return resp;
+ }
+ }
+
+ /**
+ * 查询交易结果
+ */
+ @PostMapping("/queryResult")
+ public QrcodeQueryResultResp queryResult(@ModelAttribute QrcodeQueryResultReq req) {
+ String url = "/api/thirdpay/queryResult";
+ QrcodeQueryResultResp resp = new QrcodeQueryResultResp();
+ try {
+ req.checkParam();
+ TApiClient apiClient = qrcodeConsumeService.getApiClientByAppId(req.getPartner_id());
+ if (null == apiClient) {
+ throw new ReqErrorException("请求参数错误[合作伙伴ID不存在]");
+ }
+
+ if (!req.checkSign(apiClient.getSecret())) {
+ resp.error(RespCode.SIGN_CHECK_ERROR, "签名错误");
+ print(url, resp);
+ return resp;
+ }
+
+ boolean ret = qrcodeConsumeService.doQueryQRcodeTransdtlResult(req.getPartner_id().trim(), req.getRefno(), req.getBillno(), resp);
+ if (ret) {
+ logger.info("url=[" + url + "]成功返回:" + _gson.toJson(resp));
+ } else {
+ print(url, resp);
+ }
+ return resp;
+ } catch (ReqErrorException rex) {
+ resp.error(RespCode.REQ_PARAM_ERROR, rex.getMessage());
+ print(url, resp);
+ return resp;
+ } catch (BusException bex) {
+ resp.error(RespCode.BUSINESS_PROCESS_ERROR, bex.getMessage());
+ print(url, resp);
+ return resp;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ resp.error(RespCode.OTHER_ERROR, "system error!");
+ print(url, resp);
+ return resp;
+ }
+ }
+
+ /**
+ * 查询对账单
+ */
+ @PostMapping("/queryStatement")
+ public String queryStatement(@ModelAttribute QrcodeStatementReq req) {
+ String result = "";
+ String url = "/api/thirdpay/queryStatement";
+ try {
+ req.checkParam();
+ TApiClient apiClient = qrcodeConsumeService.getApiClientByAppId(req.getPartner_id());
+ if (null == apiClient) {
+ throw new ReqErrorException("请求参数错误[合作伙伴ID不存在]");
+ }
+
+ if (!req.checkSign(apiClient.getSecret())) {
+ result = _gson.toJson(new BusApiResp(RespCode.SIGN_CHECK_ERROR, "签名错误"));
+ logger.error("url=[" + url + "]返回错误:" + result);
+ return result;
+ }
+
+ String shopaccno = systemUtilService.getBusinessValue(BusConstant.QRCODE_THIRDPAY_SHOP_PREFIX + apiClient.getAppid().trim());
+ if (StringUtil.isEmpty(shopaccno)) {
+ result = _gson.toJson(new BusApiResp(RespCode.SHOP_NOT_CONFIG, "收费商户未配置"));
+ logger.error("url=[" + url + "]返回错误:" + result);
+ return result;
+ }
+ return qrcodeConsumeService.doGetChkdtls(req.getCheckDate().trim(), shopaccno.trim());
+ } catch (ReqErrorException rex) {
+ result = _gson.toJson(new BusApiResp(RespCode.REQ_PARAM_ERROR, rex.getMessage()));
+ logger.error("url=[" + url + "]返回错误:" + result);
+ return result;
+ } catch (BusException bex) {
+ result = _gson.toJson(new BusApiResp(RespCode.BUSINESS_PROCESS_ERROR, bex.getMessage()));
+ logger.error("url=[" + url + "]返回错误:" + result);
+ return result;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ result = _gson.toJson(new BusApiResp(RespCode.OTHER_ERROR, "system error!"));
+ logger.error("url=[" + url + "]返回错误:" + result);
+ return result;
+ }
+ }
+
+
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/dao/ThirdpartQrcodeTransdtlDao.java b/src/main/java/com/supwisdom/dlpay/bus/dao/ThirdpartQrcodeTransdtlDao.java
new file mode 100644
index 0000000..e69d42f
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/dao/ThirdpartQrcodeTransdtlDao.java
@@ -0,0 +1,32 @@
+package com.supwisdom.dlpay.bus.dao;
+
+import com.supwisdom.dlpay.bus.domain.TThirdpartQrcodeTransdtl;
+import com.supwisdom.dlpay.bus.domain.TThirdpartQrcodeTransdtlPk;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Lock;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.jpa.repository.QueryHints;
+import org.springframework.stereotype.Repository;
+
+import javax.persistence.LockModeType;
+import javax.persistence.QueryHint;
+
+@Repository
+public interface ThirdpartQrcodeTransdtlDao extends JpaRepository<TThirdpartQrcodeTransdtl, TThirdpartQrcodeTransdtlPk> {
+
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
+ @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "0")})
+ @Query(value = "select t from TThirdpartQrcodeTransdtl t where t.billno = ?1 and t.appid=?2")
+ TThirdpartQrcodeTransdtl getByBillnoWithLock(String billno, String appid);
+
+ long countByQrcode(String qrcode);
+
+ TThirdpartQrcodeTransdtl getByBillnoAndAppid(String billno, String appid);
+
+ TThirdpartQrcodeTransdtl getByRefnoAndAppid(String refno, String appid);
+
+ TThirdpartQrcodeTransdtl getByCancelBillnoAndAppid(String cancelBillno, String appid);
+
+ TThirdpartQrcodeTransdtl getByCancelRefnoAndAppid(String cancelRefno,String appid);
+
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/domain/TThirdpartQrcodeTransdtl.java b/src/main/java/com/supwisdom/dlpay/bus/domain/TThirdpartQrcodeTransdtl.java
new file mode 100644
index 0000000..885ee05
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/domain/TThirdpartQrcodeTransdtl.java
@@ -0,0 +1,222 @@
+package com.supwisdom.dlpay.bus.domain;
+
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "tb_thirdpart_qrcode_transdtl",
+ indexes = {@Index(name = "idx_third_qrcodedtl_refno", columnList = "refno,appid"),
+ @Index(name = "idx_third_qrcodedtl_qrcode", columnList = "qrcode")})
+@IdClass(TThirdpartQrcodeTransdtlPk.class)
+public class TThirdpartQrcodeTransdtl {
+ @Id
+ @Column(name = "billno", nullable = false, length = 32)
+ private String billno;
+
+ @Id
+ @Column(name = "appid", nullable = false, length = 20)
+ private String appid;
+
+ @Column(name = "cardno", length = 20)
+ private String cardno;
+
+ @Column(name = "AMOUNT", precision = 12)
+ private Long amount;
+
+ @Column(name = "transdate", length = 8)
+ private String transdate;
+
+ @Column(name = "transtime", length = 6)
+ private String transtime;
+
+ @Column(name = "qrcode", length = 600)
+ private String qrcode;
+
+ @Column(name = "tac", length = 100)
+ private String tac;
+
+ @Column(name = "termdesc", length = 200)
+ private String termdesc;
+
+ @Column(name = "shopaccno", length = 20)
+ private String shopaccno;
+
+ @Column(name = "status", length = 20)
+ private String status;
+
+ @Column(name = "offlineflag")
+ private boolean offlineflag;
+
+ @Column(name = "dtltype", length = 20)
+ private String dtltype;
+
+ @Column(name = "refno", length = 32)
+ private String refno;
+
+ @Column(name = "cancel_refno", length = 32)
+ private String cancelRefno;
+
+ @Column(name = "cancel_billno", length = 32)
+ private String cancelBillno;
+
+ @Column(name = "errcode", length = 20)
+ private String errcode;
+
+ @Column(name = "errmsg", length = 600)
+ private String errmsg;
+
+ @Column(name = "createtime", length = 14)
+ private String createtime;
+
+ public String getBillno() {
+ return billno;
+ }
+
+ public void setBillno(String billno) {
+ this.billno = billno;
+ }
+
+ public String getAppid() {
+ return appid;
+ }
+
+ public void setAppid(String appid) {
+ this.appid = appid;
+ }
+
+ public String getCardno() {
+ return cardno;
+ }
+
+ public void setCardno(String cardno) {
+ this.cardno = cardno;
+ }
+
+ public Long getAmount() {
+ return amount;
+ }
+
+ public void setAmount(Long amount) {
+ this.amount = amount;
+ }
+
+ public String getTransdate() {
+ return transdate;
+ }
+
+ public void setTransdate(String transdate) {
+ this.transdate = transdate;
+ }
+
+ public String getTranstime() {
+ return transtime;
+ }
+
+ public void setTranstime(String transtime) {
+ this.transtime = transtime;
+ }
+
+ public String getQrcode() {
+ return qrcode;
+ }
+
+ public void setQrcode(String qrcode) {
+ this.qrcode = qrcode;
+ }
+
+ public String getTac() {
+ return tac;
+ }
+
+ public void setTac(String tac) {
+ this.tac = tac;
+ }
+
+ public String getTermdesc() {
+ return termdesc;
+ }
+
+ public void setTermdesc(String termdesc) {
+ this.termdesc = termdesc;
+ }
+
+ public String getShopaccno() {
+ return shopaccno;
+ }
+
+ public void setShopaccno(String shopaccno) {
+ this.shopaccno = shopaccno;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public boolean isOfflineflag() {
+ return offlineflag;
+ }
+
+ public void setOfflineflag(boolean offlineflag) {
+ this.offlineflag = offlineflag;
+ }
+
+ public String getDtltype() {
+ return dtltype;
+ }
+
+ public void setDtltype(String dtltype) {
+ this.dtltype = dtltype;
+ }
+
+ public String getRefno() {
+ return refno;
+ }
+
+ public void setRefno(String refno) {
+ this.refno = refno;
+ }
+
+ public String getCancelRefno() {
+ return cancelRefno;
+ }
+
+ public void setCancelRefno(String cancelRefno) {
+ this.cancelRefno = cancelRefno;
+ }
+
+ public String getCancelBillno() {
+ return cancelBillno;
+ }
+
+ public void setCancelBillno(String cancelBillno) {
+ this.cancelBillno = cancelBillno;
+ }
+
+ public String getErrcode() {
+ return errcode;
+ }
+
+ public void setErrcode(String errcode) {
+ this.errcode = errcode;
+ }
+
+ public String getErrmsg() {
+ return errmsg;
+ }
+
+ public void setErrmsg(String errmsg) {
+ this.errmsg = errmsg;
+ }
+
+ public String getCreatetime() {
+ return createtime;
+ }
+
+ public void setCreatetime(String createtime) {
+ this.createtime = createtime;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/domain/TThirdpartQrcodeTransdtlPk.java b/src/main/java/com/supwisdom/dlpay/bus/domain/TThirdpartQrcodeTransdtlPk.java
new file mode 100644
index 0000000..64bbe55
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/domain/TThirdpartQrcodeTransdtlPk.java
@@ -0,0 +1,59 @@
+package com.supwisdom.dlpay.bus.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+import java.io.Serializable;
+
+public class TThirdpartQrcodeTransdtlPk implements Serializable {
+ @Id
+ @Column(name = "billno", nullable = false, length = 32)
+ private String billno;
+
+ @Id
+ @Column(name = "appid", nullable = false, length = 20)
+ private String appid;
+
+ public TThirdpartQrcodeTransdtlPk() {
+ }
+
+ public TThirdpartQrcodeTransdtlPk(String billno, String appid) {
+ this.billno = billno;
+ this.appid = appid;
+ }
+
+ public String getBillno() {
+ return billno;
+ }
+
+ public void setBillno(String billno) {
+ this.billno = billno;
+ }
+
+ public String getAppid() {
+ return appid;
+ }
+
+ public void setAppid(String appid) {
+ this.appid = appid;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ TThirdpartQrcodeTransdtlPk thirdpartQrcodeTransdtlPk = (TThirdpartQrcodeTransdtlPk) o;
+ if (billno != null ? !billno.equals(thirdpartQrcodeTransdtlPk.getBillno()) : billno != null)
+ return false;
+ if (appid != null ? !appid.equals(thirdpartQrcodeTransdtlPk.getAppid()) : appid != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = billno != null ? billno.hashCode() : 0;
+ result = 31 * result + (appid != null ? appid.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/service/QrcodeConsumeService.java b/src/main/java/com/supwisdom/dlpay/bus/service/QrcodeConsumeService.java
new file mode 100644
index 0000000..4176f9b
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/service/QrcodeConsumeService.java
@@ -0,0 +1,38 @@
+package com.supwisdom.dlpay.bus.service;
+
+import com.supwisdom.dlpay.bus.bean.QrcodePayCancelResp;
+import com.supwisdom.dlpay.bus.bean.QrcodePayResp;
+import com.supwisdom.dlpay.bus.bean.QrcodeQueryResultResp;
+import com.supwisdom.dlpay.bus.domain.TThirdpartQrcodeTransdtl;
+import com.supwisdom.dlpay.framework.domain.TApiClient;
+import org.springframework.transaction.annotation.Transactional;
+
+public interface QrcodeConsumeService {
+ @Transactional(rollbackFor = Exception.class, readOnly = true)
+ TApiClient getApiClientByAppId(String appid);
+
+ @Transactional(rollbackFor = Exception.class, readOnly = true)
+ String getPayapiQRCodeRootKey(String enckey, String timestamp) throws Exception;
+
+ @Transactional(rollbackFor = Exception.class)
+ TThirdpartQrcodeTransdtl saveQRcodeTransdtl(String appid, String billno, String cardno, long amount, String transdate, String transtime,
+ String qrcode, String tac, String termdesc, String shopaccno, boolean offlineflag) throws Exception;
+
+ @Transactional(rollbackFor = Exception.class)
+ boolean doSendQRcodePayInit(TThirdpartQrcodeTransdtl transdtl, QrcodePayResp resp) throws Exception;
+
+ @Transactional(rollbackFor = Exception.class)
+ boolean doConfirmQRcodePay(String appid, String refno, String billno, QrcodePayResp resp) throws Exception;
+
+ @Transactional(rollbackFor = Exception.class)
+ boolean doCancelQRcodeTransdtl(String appid, String refno, String billno, String cancelBillno, QrcodePayCancelResp resp) throws Exception;
+
+ @Transactional(rollbackFor = Exception.class)
+ boolean doQueryQRcodeTransdtlResult(String appid, String refno, String billno, QrcodeQueryResultResp resp) throws Exception;
+
+ String doGetChkdtls(String chkdate, String shopaccno) throws Exception;
+
+ String doQueryQRcode(String uid, String userid) throws Exception;
+
+
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/service/impl/QrcodeConsumeServiceImpl.java b/src/main/java/com/supwisdom/dlpay/bus/service/impl/QrcodeConsumeServiceImpl.java
new file mode 100644
index 0000000..86c90d2
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/service/impl/QrcodeConsumeServiceImpl.java
@@ -0,0 +1,375 @@
+package com.supwisdom.dlpay.bus.service.impl;
+
+import com.supwisdom.dlpay.api.bean.*;
+import com.supwisdom.dlpay.bus.bean.QrcodePayCancelResp;
+import com.supwisdom.dlpay.bus.bean.QrcodePayResp;
+import com.supwisdom.dlpay.bus.bean.QrcodeQueryResultResp;
+import com.supwisdom.dlpay.bus.dao.ThirdpartQrcodeTransdtlDao;
+import com.supwisdom.dlpay.bus.domain.TThirdpartQrcodeTransdtl;
+import com.supwisdom.dlpay.bus.service.QrcodeConsumeService;
+import com.supwisdom.dlpay.bus.util.*;
+import com.supwisdom.dlpay.framework.dao.ApiClientDao;
+import com.supwisdom.dlpay.framework.data.SystemDateTime;
+import com.supwisdom.dlpay.framework.domain.TApiClient;
+import com.supwisdom.dlpay.framework.service.SystemUtilService;
+import com.supwisdom.dlpay.framework.util.MoneyUtil;
+import com.supwisdom.dlpay.framework.util.StringUtil;
+import com.supwisdom.dlpay.framework.util.TradeDict;
+import com.supwisdom.dlpay.paysdk.proxy.CitizenCardPayProxy;
+import com.supwisdom.dlpay.paysdk.proxy.ShopProxy;
+import com.supwisdom.dlpay.paysdk.proxy.TransactionProxy;
+import com.supwisdom.dlpay.paysdk.proxy.UserProxy;
+import com.supwisdom.dlpay.util.AesUtil;
+import org.apache.commons.codec.binary.Base64;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.Map;
+
+@Service
+public class QrcodeConsumeServiceImpl implements QrcodeConsumeService {
+ @Autowired
+ private ApiClientDao apiClientDao;
+ @Autowired
+ private ThirdpartQrcodeTransdtlDao thirdpartQrcodeTransdtlDao;
+ @Autowired
+ private SystemUtilService systemUtilService;
+
+ @Autowired
+ private CitizenCardPayProxy citizenCardPayProxy;
+ @Autowired
+ private TransactionProxy transactionProxy;
+ @Autowired
+ private ShopProxy shopProxy;
+ @Autowired
+ private UserProxy userProxy;
+
+ private String expMsg(String exp) {
+ return StringUtil.isEmpty(exp) ? "" : "|" + exp.trim();
+ }
+
+ @Override
+ public TApiClient getApiClientByAppId(String appid) {
+ return StringUtil.isEmpty(appid) ? null : apiClientDao.findByAppid(appid.trim());
+ }
+
+ @Override
+ public String getPayapiQRCodeRootKey(String enckey, String timestamp) throws Exception {
+ CitizenQrcodeKeyParam param = new CitizenQrcodeKeyParam();
+ param.setTimestamp(timestamp);
+ CitizenQrcodeKey qrcodeKey = citizenCardPayProxy.queryQrcodeKey(param);
+ if (qrcodeKey.getRetcode() != 0) {
+ throw new BusException(qrcodeKey.getRetmsg() + expMsg(qrcodeKey.getException()));
+ }
+
+ byte[] bKey = Base64.decodeBase64(qrcodeKey.getRootKey());
+ String keyBuffer = String.format("%s%04x%02x", HexUtil.encodeHex(bKey), qrcodeKey.getTotpStep() & 0xFFFF, qrcodeKey.getTotpOffset() & 0xFF);
+ String key = Base64.encodeBase64URLSafeString(HexUtil.decodeHex(keyBuffer)); //rootkey + step + offset
+
+ final String json = "{\"rootKey\":\"" + key + "\",\"iv\":\"" + qrcodeKey.getIv() + "\",\"offsetSec\":\"" + qrcodeKey.getOffsetSec() + "\"}";
+ final String encData = AesUtil.encrypt(json, enckey); //用appKey加密
+// final String decData = AesUtil.decrypt(encData, enckey);
+ return encData;
+ }
+
+ @Override
+ public TThirdpartQrcodeTransdtl saveQRcodeTransdtl(String appid, String billno, String cardno, long amount, String transdate, String transtime, String qrcode, String tac, String termdesc, String shopaccno, boolean offlineflag) throws Exception {
+ TThirdpartQrcodeTransdtl transdtl = thirdpartQrcodeTransdtlDao.getByBillnoWithLock(billno, appid);
+ if (null != transdtl) {
+ if (cardno.equals(transdtl.getCardno()) && amount == transdtl.getAmount() && transdate.equals(transdtl.getTransdate())
+ && transtime.equals(transdtl.getTranstime()) && qrcode.equals(transdtl.getQrcode()) && tac.equals(transdtl.getTac())) {
+ if (BusConstant.STATUS_TRANSDTL_INIT.equals(transdtl.getStatus()) && StringUtil.isEmpty(transdtl.getRefno())) {
+ return transdtl; //重复请求
+ } else {
+ throw new BusException("该商户订单已提交交易请求,请查询结果!");
+ }
+ }
+ throw new BusException("商户订单号重复!");
+ }
+
+ if (thirdpartQrcodeTransdtlDao.countByQrcode(qrcode) > 0) {
+ throw new BusException("二维码已使用!");
+ }
+
+ transdtl = new TThirdpartQrcodeTransdtl();
+ transdtl.setBillno(billno);
+ transdtl.setAppid(appid);
+ transdtl.setCardno(cardno);
+ transdtl.setAmount(amount);
+ transdtl.setTransdate(transdate);
+ transdtl.setTranstime(transtime);
+ transdtl.setQrcode(qrcode);
+ transdtl.setTac(tac);
+ transdtl.setTermdesc(termdesc);
+ transdtl.setShopaccno(shopaccno);
+ transdtl.setStatus(BusConstant.STATUS_TRANSDTL_INIT);
+ transdtl.setDtltype("carbus"); //fixme: 可根据appid切换
+ transdtl.setOfflineflag(offlineflag);
+ transdtl.setCreatetime(systemUtilService.getSysdatetime().getHostdatetime());
+ thirdpartQrcodeTransdtlDao.save(transdtl);
+ return transdtl;
+ }
+
+
+ @Override
+ public boolean doSendQRcodePayInit(TThirdpartQrcodeTransdtl transdtl, QrcodePayResp resp) throws Exception {
+ resp.setRetcode(RespCode.REQ_PAYAPI_ERROR);
+
+ CitizenQrcodePayinitParam param = new CitizenQrcodePayinitParam();
+ param.setQrcode(transdtl.getQrcode());
+ param.setQrcodeType(transdtl.isOfflineflag() ? "offline" : "online");
+ param.setShopaccno(transdtl.getShopaccno());
+ param.setAmount(transdtl.getAmount().intValue());
+ param.setBillno(transdtl.getBillno());
+ param.setTransdate(transdtl.getTransdate());
+ param.setTranstime(transdtl.getTranstime());
+ param.setDtltype(transdtl.getDtltype());
+ param.setCardNo(transdtl.getCardno());
+ param.setTac(transdtl.getTac());
+
+ CitizenPayResponse response = citizenCardPayProxy.citizencardQrcodePayinit(param);
+ if (response.getRetcode() != 0) {
+ transdtl.setErrcode(RespCode.BUSINESS_PROCESS_ERROR);
+ transdtl.setErrmsg("向核心平台初始化下单失败!" + response.getRetmsg() + expMsg(response.getException()));
+ thirdpartQrcodeTransdtlDao.save(transdtl);
+
+ resp.setRetmsg(response.getRetmsg()+expMsg(response.getException()));
+ return false;
+ }
+
+ transdtl.setRefno(response.getRefno());
+ transdtl.setErrcode("0");
+ transdtl.setErrmsg("向核心平台初始化下单成功!");
+ thirdpartQrcodeTransdtlDao.save(transdtl);
+
+ resp.setRetcode(RespCode.SUCCESS);
+ resp.setRetmsg("success");
+ resp.setAmount(MoneyUtil.YuanToFen(response.getAmount()));
+ resp.setBillno(response.getBillno());
+ resp.setRefno(response.getRefno());
+ return true;
+ }
+
+ @Override
+ public boolean doConfirmQRcodePay(String appid, String refno, String billno, QrcodePayResp resp) throws Exception {
+ TThirdpartQrcodeTransdtl transdtl = null;
+ if (!StringUtil.isEmpty(billno)) {
+ transdtl = thirdpartQrcodeTransdtlDao.getByBillnoAndAppid(billno.trim(), appid);
+ if (null != transdtl && !StringUtil.isEmpty(refno) && !refno.trim().equals(transdtl.getRefno())) {
+ throw new ReqErrorException("请求参数错误[商户订单号与平台流水号不一致]");
+ }
+ } else {
+ transdtl = thirdpartQrcodeTransdtlDao.getByRefnoAndAppid(refno.trim(), appid);
+ }
+
+ if (null == transdtl) {
+ throw new ReqErrorException("请求参数错误[流水号错误,流水不存在]");
+ } else if (StringUtil.isEmpty(transdtl.getRefno())) {
+ throw new BusException("订单初始化失败!");
+ } else if (Arrays.asList(TradeDict.DTL_STATUS_SUCCESS, TradeDict.DTL_STATUS_FAIL).contains(transdtl.getStatus())) {
+ throw new BusException("订单已经确认过,请直接查询结果!");
+ }
+
+ CitizenCardPayfinishParam param = new CitizenCardPayfinishParam();
+ param.setRefno(transdtl.getRefno());
+
+ CitizenPayResponse response = citizenCardPayProxy.citizencardPayFinish(param);
+ if (response.getRetcode() != 0) {
+ //失败
+ if (response.getRetcode() == 55555) {
+ transdtl.setStatus(TradeDict.DTL_STATUS_WIP);
+ transdtl.setErrcode(RespCode.USER_PAYING_ERROR);
+ transdtl.setErrmsg("用户支付中,请稍后查询流水结果");
+ } else {
+ transdtl.setStatus(TradeDict.DTL_STATUS_FAIL);
+ transdtl.setErrcode(RespCode.USER_PAY_FAIL);
+ transdtl.setErrmsg(response.getRetmsg()+expMsg(response.getException()));
+ }
+ thirdpartQrcodeTransdtlDao.save(transdtl);
+ resp.error(transdtl.getErrcode(), transdtl.getErrmsg());
+ return false;
+ }
+
+ //扣款成功
+ transdtl.setStatus(TradeDict.DTL_STATUS_SUCCESS);
+ transdtl.setErrcode("0");
+ transdtl.setErrmsg(null);
+ thirdpartQrcodeTransdtlDao.save(transdtl);
+
+ resp.setRetcode(RespCode.SUCCESS);
+ resp.setRetmsg("success");
+ resp.setBillno(response.getBillno());
+ resp.setRefno(response.getRefno());
+ resp.setAmount(MoneyUtil.YuanToFen(response.getAmount()));
+ return true;
+ }
+
+ @Override
+ public boolean doCancelQRcodeTransdtl(String appid, String refno, String billno, String cancelBillno, QrcodePayCancelResp resp) throws Exception {
+ TThirdpartQrcodeTransdtl transdtl = null;
+ if (!StringUtil.isEmpty(billno)) {
+ transdtl = thirdpartQrcodeTransdtlDao.getByBillnoAndAppid(billno.trim(), appid);
+ if (null != transdtl && !StringUtil.isEmpty(refno) && !refno.trim().equals(transdtl.getRefno())) {
+ throw new ReqErrorException("请求参数错误[商户订单号与平台流水号不一致]");
+ }
+ } else {
+ transdtl = thirdpartQrcodeTransdtlDao.getByRefnoAndAppid(refno.trim(), appid);
+ }
+
+ if (null == transdtl) {
+ throw new ReqErrorException("请求参数错误[流水号错误,原始交易流水不存在]");
+ } else if (StringUtil.isEmpty(transdtl.getRefno())) {
+ throw new BusException("原始交易订单初始化失败!");
+ } else if (null != transdtl.getCancelBillno() && !cancelBillno.equals(transdtl.getCancelBillno())) {
+ throw new BusException("原始交易订单已提交过撤销!已有撤销单号:" + transdtl.getCancelBillno());
+ }
+
+ SystemDateTime dt = systemUtilService.getSysdatetime();
+ ConsumePayCancelParam param = new ConsumePayCancelParam();
+ param.setBillno(transdtl.getBillno());
+ param.setRefno(transdtl.getRefno());
+ param.setShopaccno(transdtl.getShopaccno());
+ param.setRequestbillno(cancelBillno);
+ param.setTransdate(dt.getHostdate());
+ param.setTranstime(dt.getHosttime());
+
+ PayReverseResponse response = transactionProxy.payCancel(param);
+ transdtl.setCancelBillno(cancelBillno);
+ if (!StringUtil.isEmpty(response.getRefno())) {
+ transdtl.setCancelRefno(response.getRefno());
+ }
+ if (response.getRetcode() != 0) {
+ //失败
+ if (response.getRetcode() == 55555) {
+ transdtl.setErrcode(RespCode.CANCEL_PAYING_ERROR);
+ transdtl.setErrmsg("撤销或退款处理中,请稍后查询处理结果");
+ } else {
+ transdtl.setErrcode(RespCode.CANCEL_FAIL);
+ transdtl.setErrmsg("撤销失败!" + response.getRetmsg()+expMsg(response.getException()));
+ }
+ thirdpartQrcodeTransdtlDao.save(transdtl);
+ resp.error(transdtl.getErrcode(), transdtl.getErrmsg());
+ return false;
+ }
+
+ //成功
+ transdtl.setStatus(TradeDict.DTL_STATUS_CANCEL);
+ transdtl.setErrcode("00");
+ transdtl.setErrmsg("撤销成功!");
+ thirdpartQrcodeTransdtlDao.save(transdtl);
+
+ resp.setRetcode(RespCode.SUCCESS);
+ resp.setRetmsg("撤销成功!");
+ resp.setRefno(response.getRefno());
+ return true;
+ }
+
+ @Override
+ public boolean doQueryQRcodeTransdtlResult(String appid, String refno, String billno, QrcodeQueryResultResp resp) throws Exception {
+ boolean revflag = false;
+ TThirdpartQrcodeTransdtl transdtl = null;
+ if (!StringUtil.isEmpty(billno)) {
+ transdtl = thirdpartQrcodeTransdtlDao.getByBillnoAndAppid(billno.trim(), appid);
+ if (null != transdtl && !StringUtil.isEmpty(refno) && !StringUtil.isEmpty(transdtl.getRefno())
+ && !refno.trim().equals(transdtl.getRefno())) {
+ throw new ReqErrorException("请求参数错误[商户订单号与平台流水号不一致]");
+ }
+ } else {
+ transdtl = thirdpartQrcodeTransdtlDao.getByRefnoAndAppid(refno.trim(), appid);
+ }
+
+ if (null == transdtl) {
+ if (!StringUtil.isEmpty(billno)) {
+ transdtl = thirdpartQrcodeTransdtlDao.getByCancelBillnoAndAppid(billno, appid);
+ if (null != transdtl && !StringUtil.isEmpty(refno) && !StringUtil.isEmpty(transdtl.getCancelRefno())
+ && !refno.trim().equals(transdtl.getCancelRefno())) {
+ throw new ReqErrorException("请求参数错误[商户订单号与平台流水号不一致]");
+ }
+ } else {
+ transdtl = thirdpartQrcodeTransdtlDao.getByCancelRefnoAndAppid(refno.trim(), appid);
+ }
+ if (null != transdtl) revflag = true; //查询的撤销流水
+ }
+
+ if (null == transdtl) {
+ throw new ReqErrorException("请求参数错误[流水号错误,交易流水不存在]");
+ }
+
+ QueryDtlResultParam param = new QueryDtlResultParam();
+ param.setBillno(null != billno ? billno.trim() : null);
+ param.setRefno(null != refno ? refno.trim() : null);
+ param.setShopaccno(transdtl.getShopaccno());
+
+ QueryTransDtlResponse response = transactionProxy.queryDtlResult(param);
+ if (response.getRetcode() != 0) {
+ resp.error(RespCode.BUSINESS_PROCESS_ERROR, response.getRetmsg()+expMsg(response.getException()));
+ return false;
+ }
+
+ if ("success".equals(response.getStatus())) {
+ //明确流水成功,修改一些状态
+ if (revflag && !TradeDict.DTL_STATUS_CANCEL.equals(transdtl.getStatus())) {
+ transdtl.setStatus(TradeDict.DTL_STATUS_CANCEL);
+ transdtl.setErrcode("00");
+ transdtl.setErrmsg("撤销成功!");
+ thirdpartQrcodeTransdtlDao.save(transdtl);
+ } else if (!revflag && !TradeDict.DTL_STATUS_SUCCESS.equals(transdtl.getStatus())) {
+ transdtl.setStatus(TradeDict.DTL_STATUS_SUCCESS);
+ transdtl.setErrcode("0");
+ transdtl.setErrmsg(null);
+ thirdpartQrcodeTransdtlDao.save(transdtl);
+ }
+ } else if ("fail".equals(response.getStatus())) {
+ //明确流水失败
+ if (revflag) {
+ transdtl.setErrcode(RespCode.CANCEL_FAIL);
+ transdtl.setErrmsg("撤销失败!" + expMsg(response.getRemark()));
+ thirdpartQrcodeTransdtlDao.save(transdtl);
+ } else {
+ transdtl.setStatus(TradeDict.DTL_STATUS_FAIL);
+ transdtl.setErrcode(RespCode.USER_PAY_FAIL);
+ transdtl.setErrmsg("查询结果为失败!" + expMsg(response.getRemark()));
+ thirdpartQrcodeTransdtlDao.save(transdtl);
+ }
+ }
+
+ resp.setRetcode(RespCode.SUCCESS);
+ resp.setRetmsg("success");
+ resp.setBillno(response.getOutTradeNo());
+ resp.setRefno(response.getRefno());
+ resp.setAmount(MoneyUtil.YuanToFen(response.getAmount()));
+ resp.setStatus(response.getStatus());
+ resp.setCardno(response.getPayinfo());
+ resp.setSourceType(response.getSourceType());
+ resp.setReverseFlag(response.getReverseFlag());
+ resp.setTransdesc(response.getTransdesc());
+ resp.setRemark(response.getRemark());
+ resp.setTermdesc(transdtl.getTermdesc());
+ return true;
+ }
+
+ @Override
+ public String doGetChkdtls(String chkdate, String shopaccno) throws Exception {
+ DownloadShopBillParam param = new DownloadShopBillParam();
+ param.setCheckdate(chkdate);
+ param.setShopaccno(shopaccno);
+ return shopProxy.downloadShopBill(param);
+ }
+
+ @Override
+ public String doQueryQRcode(String uid, String userid) throws Exception {
+ QrcodeParam param = new QrcodeParam();
+ param.setUid(uid);
+ param.setUserid(userid);
+
+ Map<String, Object> response = userProxy.qrcode(param);
+ final String retcode = response.get("retcode") != null ? response.get("retcode").toString() : "99";
+ final String retmsg = response.get("retmsg") != null ? response.get("retmsg").toString() : "请求生成二维码失败!";
+ if ("0".equals(retcode)) {
+ return response.get("qrcode").toString();
+ }
+
+ throw new ReqErrorException(retmsg);
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/task/BusPayTask.java b/src/main/java/com/supwisdom/dlpay/bus/task/BusPayTask.java
index 235277a..149a0cd 100644
--- a/src/main/java/com/supwisdom/dlpay/bus/task/BusPayTask.java
+++ b/src/main/java/com/supwisdom/dlpay/bus/task/BusPayTask.java
@@ -17,6 +17,7 @@
import com.supwisdom.dlpay.restaurant.service.OfflineTransDtlService;
import com.supwisdom.dlpay.restaurant.service.TransDtlService;
import com.supwisdom.dlpay.restaurant.util.RestaurantConstant;
+import net.javacrumbs.shedlock.core.SchedulerLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -47,7 +48,8 @@
@Autowired
private TransactionProxy transactionProxy;
- @Scheduled(cron = "0 0/1 * * * ?")
+ @Scheduled(cron = "${busapp.upload.transdtl.task.cron}")
+ @SchedulerLock(name = "BuspayUploadTransdtlTask", lockAtMostForString = "PT10M")
private void submitOfflineDtlTask() {
String date = DateUtil.getNow("yyyyMMdd");
List<TOfflineBusdtl> dtls = busConsumeService.getUncheckOfflineTransdtl(date);
diff --git a/src/main/java/com/supwisdom/dlpay/bus/util/BusConstant.java b/src/main/java/com/supwisdom/dlpay/bus/util/BusConstant.java
index da255ac..d6ba66d 100644
--- a/src/main/java/com/supwisdom/dlpay/bus/util/BusConstant.java
+++ b/src/main/java/com/supwisdom/dlpay/bus/util/BusConstant.java
@@ -1,10 +1,10 @@
package com.supwisdom.dlpay.bus.util;
public class BusConstant {
- public final static String PAYAPI_CONNECT_VERSION="1.0";
- public final static String PAYAPI_CONNECT_SIGNTYPE="MD5";
- public final static String PAYAPI_CONNECT_TENANTID="tenantid";
- public final static String PAYAPI_CONNECT_SIGNKEY="c9ae5b4fe5014b5b9eb19e1a0797a3a3";
+ public final static String PAYAPI_CONNECT_VERSION = "1.0";
+ public final static String PAYAPI_CONNECT_SIGNTYPE = "MD5";
+ public final static String PAYAPI_CONNECT_TENANTID = "tenantid";
+ public final static String PAYAPI_CONNECT_SIGNKEY = "c9ae5b4fe5014b5b9eb19e1a0797a3a3";
public final static String PAYAPI_CARDSYNC_DEFAULTTIME = "00000000000000"; //yyyyMMddhhmmss
@@ -12,10 +12,10 @@
public final static String CARDVERNO_DEFAULT = "00000000000000"; //yyMMdd+8位递增数
- public final static String STATUS_CARDVER_NORMAL="normal";
- public final static String STATUS_CARDVER_CLOSED="closed";
+ public final static String STATUS_CARDVER_NORMAL = "normal";
+ public final static String STATUS_CARDVER_CLOSED = "closed";
- public final static String PAYAPI_CARDSYNC_ONCECOUNT="payapi.cardsync.oncecount";
+ public final static String PAYAPI_CARDSYNC_ONCECOUNT = "payapi.cardsync.oncecount";
public final static int PAYAPI_CARDSYNC_ONCECOUNT_DEFAULT = 20000;
@@ -33,10 +33,10 @@
public final static int SYSPARAID_MAXBLACKCARDVERNO = 11; //全局参数,最大黑名单版本号
public final static int SYSPARAID_CARDSYNCTIME = 21; //全局参数,卡同步时间
- public final static String STATUS_NORMAL="normal";
- public final static String STATUS_INIT="init";
- public final static String STATUS_WAIT="wip";
- public final static String TRANSMODE_BUS="bus";
+ public final static String STATUS_NORMAL = "normal";
+ public final static String STATUS_INIT = "init";
+ public final static String STATUS_WAIT = "wip";
+ public final static String TRANSMODE_BUS = "bus";
public final static String BUS_OFFLINE_NODEVICE = "11";
public final static String BUS_OFFLINE_NOUSER = "12";
@@ -55,7 +55,9 @@
public static final String STATUS_TRANSDTL_WAIT = "wip"; //提交中
public static final String STATUS_TRANSDTL_SUCCESS = "success"; //已入账
public static final String STATUS_TRANSDTL_FAIL = "fail"; //取消
- public static final String TRANSTYPE_TRANSDTL_REVERT = "revert"; //取消
+ public static final String TRANSTYPE_TRANSDTL_REVERT = "revert"; //取消
+ public final static String QRCODE_THIRDPAY_SHOP_PREFIX = "thirdpart.qrcode.shopaccno.";
+
}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/util/HexUtil.java b/src/main/java/com/supwisdom/dlpay/bus/util/HexUtil.java
new file mode 100644
index 0000000..8fea8c5
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/util/HexUtil.java
@@ -0,0 +1,25 @@
+package com.supwisdom.dlpay.bus.util;
+
+public class HexUtil {
+ public static byte[] decodeHex(String data) {
+ if (data == null || data.length() % 2 != 0) {
+ throw new RuntimeException("decodeHex data length must be divided by 2");
+ }
+ byte[] result = new byte[data.length() / 2];
+ for (int i = 0; i < data.length(); i += 2) {
+ result[i / 2] = (byte) Integer.parseInt(data.substring(i, i + 2), 16);
+ }
+ return result;
+ }
+
+ public static String encodeHex(byte[] data) {
+ if (data == null) {
+ throw new RuntimeException("encodeHex data must be not null");
+ }
+ StringBuilder sb = new StringBuilder();
+ for (byte datum : data) {
+ sb.append(String.format("%02x", datum & 0xFF));
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/util/ReqErrorException.java b/src/main/java/com/supwisdom/dlpay/bus/util/ReqErrorException.java
new file mode 100644
index 0000000..0de642c
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/util/ReqErrorException.java
@@ -0,0 +1,7 @@
+package com.supwisdom.dlpay.bus.util;
+
+public class ReqErrorException extends Exception {
+ public ReqErrorException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/bus/util/RespCode.java b/src/main/java/com/supwisdom/dlpay/bus/util/RespCode.java
new file mode 100644
index 0000000..a812295
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/bus/util/RespCode.java
@@ -0,0 +1,18 @@
+package com.supwisdom.dlpay.bus.util;
+
+public class RespCode {
+ public static final String SUCCESS="0";
+
+ public static final String BUSINESS_PROCESS_ERROR = "30"; //业务处理过程中的错误
+ public static final String REQ_PARAM_ERROR = "31"; //请求参数错误
+ public static final String SHOP_NOT_CONFIG = "32"; //收费商户未配置
+ public static final String REQ_PAYAPI_ERROR = "33"; //请求核心平台返回错误
+ public static final String SIGN_CHECK_ERROR = "34"; //签名验证错误
+ public static final String USER_PAYING_ERROR = "35"; //用户支付中
+ public static final String USER_PAY_FAIL = "36"; //扣费败失
+ public static final String CANCEL_PAYING_ERROR = "37"; //撤销或退款处理中
+ public static final String CANCEL_FAIL = "38"; //撤销或退款处理中
+
+ public static final String OTHER_ERROR = "99"; //其他错误
+
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/StringUtil.java b/src/main/java/com/supwisdom/dlpay/framework/util/StringUtil.java
index c642200..903bcca 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/StringUtil.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/StringUtil.java
@@ -148,5 +148,20 @@
return true;
}
+ public static Map<String, String> swParaFilter(Map<String, String> sArray) {
+ Map<String, String> result = new HashMap<String, String>();
+ if (sArray == null || sArray.size() <= 0) {
+ return result;
+ }
+ for (String key : sArray.keySet()) {
+ String value = sArray.get(key);
+ if (null == value || "".equals(value.trim()) || key.equalsIgnoreCase("sign")) {
+ continue;
+ }
+ result.put(key, value);
+ }
+ return result;
+ }
+
}
diff --git a/src/main/java/com/supwisdom/dlpay/restaurant/task/RestaurantTask.java b/src/main/java/com/supwisdom/dlpay/restaurant/task/RestaurantTask.java
index 3c9e0a2..c02b8a9 100644
--- a/src/main/java/com/supwisdom/dlpay/restaurant/task/RestaurantTask.java
+++ b/src/main/java/com/supwisdom/dlpay/restaurant/task/RestaurantTask.java
@@ -15,6 +15,7 @@
import com.supwisdom.dlpay.restaurant.service.OfflineTransDtlService;
import com.supwisdom.dlpay.restaurant.service.TransDtlService;
import com.supwisdom.dlpay.restaurant.util.RestaurantConstant;
+import net.javacrumbs.shedlock.core.SchedulerLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -40,7 +41,8 @@
@Autowired
private UserProxy userProxy;
- @Scheduled(cron = "0 0/1 * * * ? ")
+ @Scheduled(cron = "${restaurant.sync.card.task.cron}")
+ @SchedulerLock(name = "RestaurantSyncCardTask", lockAtMostForString = "PT20M")
private void CustomerCheckTask(){
CustomerSearchBean searchBean=new CustomerSearchBean();
searchBean.setCheckstatus(RestaurantConstant.STATUS_CHECKSTATUS_UNCHECK);
diff --git a/src/main/java/com/supwisdom/dlpay/util/AesUtil.java b/src/main/java/com/supwisdom/dlpay/util/AesUtil.java
new file mode 100644
index 0000000..c3e938b
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/util/AesUtil.java
@@ -0,0 +1,161 @@
+package com.supwisdom.dlpay.util;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+public class AesUtil {
+
+ public static String encrypt(String rawdata, String secret) {
+ Cipher cipher;
+ try {
+ cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+ SecretKeySpec key = new SecretKeySpec(secret.getBytes("UTF-8"), "AES");
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ byte[] encdata = cipher.doFinal(rawdata.getBytes("UTF-8"));
+ String hexdata = Base64.encodeBase64String(encdata);
+
+ return hexdata;
+ } catch (NoSuchAlgorithmException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalBlockSizeException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (BadPaddingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+
+ }
+ public static String encryptCFB(String rawdata, String secret ,String ivstr,String KEY_ALG_MODE) {
+ Cipher cipher;
+ try {
+ //byte[] iv = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF };
+ byte[] iv = Hex.decodeHex(ivstr.toCharArray());
+ IvParameterSpec ivSpec = new IvParameterSpec(iv);
+ cipher = Cipher.getInstance(KEY_ALG_MODE);
+ SecretKeySpec key = new SecretKeySpec(Base64.decodeBase64(secret), "AES");
+ cipher.init(Cipher.ENCRYPT_MODE, key,ivSpec);
+ byte[] encdata = cipher.doFinal(rawdata.getBytes("UTF-8"));
+ String hexdata = Base64.encodeBase64String(encdata);
+
+ return hexdata;
+ } catch (NoSuchAlgorithmException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalBlockSizeException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (BadPaddingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InvalidAlgorithmParameterException e) {
+ e.printStackTrace();
+ } catch (DecoderException e) {
+ e.printStackTrace();
+ }
+ return null;
+
+ }
+
+ public static String decrypt(String encdata, String secret){
+ Cipher cipher;
+ try {
+ cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+ SecretKeySpec key = new SecretKeySpec(secret.getBytes("UTF-8"), "AES");
+ cipher.init(Cipher.DECRYPT_MODE, key);
+ byte[] decordedValue = Base64.decodeBase64(encdata);
+ byte[] decdata = cipher.doFinal(decordedValue);
+ String rawdata = new String(decdata);
+
+ return rawdata;
+ } catch (NoSuchAlgorithmException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalBlockSizeException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (BadPaddingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static String decryptCFB(String encdata, String secret,String ivstr,String KEY_ALG_MODE){
+ Cipher cipher;
+ try {
+// byte[] iv = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF };
+ byte[] iv = Hex.decodeHex(ivstr.toCharArray());
+ IvParameterSpec ivSpec = new IvParameterSpec(iv);
+ cipher = Cipher.getInstance(KEY_ALG_MODE);
+ SecretKeySpec key = new SecretKeySpec(Base64.decodeBase64(secret), "AES");
+ cipher.init(Cipher.DECRYPT_MODE, key,ivSpec);
+ byte[] decordedValue = Base64.decodeBase64(encdata);
+ byte[] decdata = cipher.doFinal(decordedValue);
+ String rawdata = new String(decdata);
+
+ return rawdata;
+ } catch (NoSuchAlgorithmException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalBlockSizeException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (BadPaddingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InvalidAlgorithmParameterException e) {
+ e.printStackTrace();
+ } catch (DecoderException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/src/main/kotlin/com/supwisdom/dlpay/security.kt b/src/main/kotlin/com/supwisdom/dlpay/security.kt
index d4166cb..8d8609f 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/security.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/security.kt
@@ -120,6 +120,7 @@
UsernamePasswordAuthenticationFilter::class.java)
.antMatcher("/api/**")
.authorizeRequests()
+ .antMatchers("/api/thirdpay/**").permitAll()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/thirdpart/**").permitAll()
.antMatchers("/api/notify/**").permitAll()
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index a606a3a..1f8d6fd 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,5 +1,5 @@
-#######################################springboot配置 start#################################
-# 单库数据库配置
+#######################################springboot\u914D\u7F6E start#################################
+# \u5355\u5E93\u6570\u636E\u5E93\u914D\u7F6E
spring.jpa.show-sql=false
spring.datasource.hikari.connection-timeout=60000
spring.datasource.hikari.maximum-pool-size=5
@@ -31,8 +31,11 @@
cron.offlinedtl=0/10 * * * * ?
-# 对账任务
+# \u5BF9\u8D26\u4EFB\u52A1
restaurant.chkdtltask.cron=27 3/10 * * * ?
-# 统计任务
+# \u7EDF\u8BA1\u4EFB\u52A1
restaurant.statement.cron=0 7/10 * * * ?
+# \u5361\u540C\u6B65\u4EFB\u52A1
+restaurant.sync.card.task.cron=0 0/1 * * * ?
+busapp.upload.transdtl.task.cron=0 0/1 * * * ?
\ No newline at end of file