Browse Source

增加cuspay报关功接口及异步通知商户接口

zx 7 years ago
parent
commit
726c2ed86f

+ 1 - 1
src/main/java/com/emato/cuspay/dao/mapper/wx/WxCbPayDocMapper.java

@@ -20,7 +20,7 @@ public interface WxCbPayDocMapper {
 
     int updateByPrimaryKeySelective(WxCbPayDoc record);
 
-    List<WxCbPayDoc> selectBeDeclared();
+    List<WxCbPayDoc> selectBeDeclaredData(Integer limit);
 
     List<WxCbPayDoc> selectNotify();
 

+ 16 - 0
src/main/java/com/emato/cuspay/declare/CusDeclare.java

@@ -0,0 +1,16 @@
+package com.emato.cuspay.declare;
+
+/**
+ * 海关申报接口
+ * @author zx
+ * @version 1.0
+ * 2018-05-18 11:01
+ */
+public interface CusDeclare {
+
+    /**
+     * 海关报关
+     */
+    void declare();
+
+}

+ 217 - 0
src/main/java/com/emato/cuspay/declare/WxCusDeclare.java

@@ -0,0 +1,217 @@
+package com.emato.cuspay.declare;
+
+import com.emato.cuspay.dao.data.MerchCusCfg;
+import com.emato.cuspay.dao.data.MerchPayCfg;
+import com.emato.cuspay.dao.data.wx.WxCbPayDoc;
+import com.emato.cuspay.dao.data.wx.WxPayError;
+import com.emato.cuspay.dao.mapper.wx.WxCbPayDocMapper;
+import com.emato.cuspay.dto.WxResponseMsg;
+import com.emato.cuspay.notify.WxMerchantNotice;
+import com.emato.cuspay.util.OkHttpUtils;
+import com.emato.cuspay.util.XmlUtils;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import okhttp3.MediaType;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.xml.bind.JAXB;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+
+/**
+ * 微信海关申报
+ * @author zx
+ * @version 1.0
+ * 2018-05-18 11:04
+ */
+
+@Component
+public class WxCusDeclare implements CusDeclare{
+
+    private static final Logger logger = LoggerFactory.getLogger(WxCusDeclare.class);
+
+
+    @Value("${db.wx.notify.limit}")
+    private Integer limit;
+
+    @Value("${wx.payment.query.url}")
+    private String declareURL;
+
+
+    @Autowired
+    WxCbPayDocMapper wxCbPayDocMapper;
+
+    /**
+     * 海关报关接口
+     */
+    public void declare() {
+        limit = (limit != null && limit > 0) ? limit : 20;
+        List<WxCbPayDoc> wxCbPayDocs = wxCbPayDocMapper.selectBeDeclaredData(limit);
+
+        if (wxCbPayDocs == null || wxCbPayDocs.isEmpty()) {
+            logger.info("没有待申报微信推海关的支付数据");
+            return;
+        }
+
+        //记录异常数据
+        List<WxCbPayDoc> docs = Lists.newArrayList();
+        List<WxPayError> errors = Lists.newArrayList();
+
+        wxCbPayDocs.forEach(wxCbPayDoc -> {
+            //获取商户信息 从缓存中去  缓存不存在 从数据库重取
+            MerchPayCfg merchPayCfg = null;
+
+            if (merchPayCfg == null) {
+                logger.error("商户编号为【"+wxCbPayDoc.getMerchSn()+"】的商户支付配置信息不存在");
+                return;
+            }
+
+            if (merchPayCfg.getMerchWxApiKey() == null) {
+                logger.error("商户编号为【"+wxCbPayDoc.getMerchSn()+"】的商户支付信息api密钥为空");
+                return;
+            }
+
+            //组装xml 格式数据
+            String xml = XmlUtils.map2Xml(assemblyDeclareXml(wxCbPayDoc, merchPayCfg.getMerchWxApiKey()));
+
+            //通过http post请求 发送xml数据
+            Request request = OkHttpUtils.buildRequest(declareURL,
+                        RequestBody.create(MediaType.parse("application/xml; charset=utf-8"), xml));
+            String result = null;
+            try {
+                result = OkHttpUtils.post(request);
+                StringReader reader = new StringReader(result);
+                WxResponseMsg wxResponseMsgDto = JAXB.unmarshal(reader, WxResponseMsg.class);
+                logger.info("result:"+result + "wx response message pojo:"+wxResponseMsgDto);
+            } catch (IOException e) {
+                docs.add(wxCbPayDoc);
+                WxPayError wxPayError = new WxPayError();
+                errors.add(wxPayError);
+            }
+        });
+
+        //存储异常记录
+
+    }
+
+    /**
+     * 组装报关所需要的报关数据
+     * @param wxCbPayDoc 微信支付数据
+     * @param key 微信Api密钥
+     * @return
+     */
+    protected Map<String, String> assemblyDeclareXml(WxCbPayDoc wxCbPayDoc, String key) {
+
+
+        //1.选择报关数据,排序
+        SortedMap<String, String> sorted = Maps.newTreeMap();
+        sorted.put("appid", wxCbPayDoc.getAppid());
+        sorted.put("mch_id", wxCbPayDoc.getMchId());
+        sorted.put("out_trade_no", wxCbPayDoc.getOutTradeNo());
+        sorted.put("transaction_id", wxCbPayDoc.getTransactionId());
+        sorted.put("customs", wxCbPayDoc.getCustoms());
+        sorted.put("mch_customs_no", wxCbPayDoc.getMchCustomsNo());
+        if (wxCbPayDoc.getDuty() != null) {
+            sorted.put("duty", String.valueOf(wxCbPayDoc.getDuty()));
+        }
+        if (wxCbPayDoc.getActionType() != null) {
+            sorted.put("action_type", wxCbPayDoc.getActionType());
+        }
+        if (wxCbPayDoc.getSubOrderNo() != null) {
+            sorted.put("sub_order_no", wxCbPayDoc.getActionType());
+        }
+        if (wxCbPayDoc.getFeeType() != null) {
+            sorted.put("fee_type", wxCbPayDoc.getFeeType());
+        }
+        if (wxCbPayDoc.getOrderFee() != null) {
+            sorted.put("order_fee", String.valueOf(wxCbPayDoc.getOrderFee()));
+        }
+        if (wxCbPayDoc.getTransportFee() != null) {
+            sorted.put("transport_fee", String.valueOf(wxCbPayDoc.getTransportFee()));
+        }
+        if (wxCbPayDoc.getProductFee() != null) {
+            sorted.put("product_fee", String.valueOf(wxCbPayDoc.getProductFee()));
+        }
+        if (wxCbPayDoc.getCertType() != null ) {
+            sorted.put("cert_type", wxCbPayDoc.getCertType());
+        }
+        if (wxCbPayDoc.getCertId() != null) {
+            sorted.put("cert_id", wxCbPayDoc.getCertId());
+        }
+        if (wxCbPayDoc.getName() != null) {
+            sorted.put("name", wxCbPayDoc.getName());
+        }
+
+        //2.生成签名
+        StringBuilder sb = new StringBuilder();
+        for (Map.Entry<String,String> entry : sorted.entrySet()) {
+            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
+        }
+        sb.append("key").append("=").append(key);
+        //签名MD5 加密
+        String sign = DigestUtils.md5Hex(sb.toString()).toUpperCase();
+
+        sorted.put("sign", sign);
+        return sorted;
+    }
+
+    public static void main(String[] args) {
+        WxCbPayDoc wxCbPayDoc = new WxCbPayDoc();
+        wxCbPayDoc.setAppid("wxd678efh567hg6787");
+        wxCbPayDoc.setMchId("1501125641");
+        wxCbPayDoc.setOutTradeNo("20150806125346");
+        wxCbPayDoc.setTransactionId("1000320306201511078440737890");
+        wxCbPayDoc.setCustoms("SHENZHEN");
+        wxCbPayDoc.setMchCustomsNo("4403160Z3Y");//中网科技(深圳)有限公司
+
+
+        SortedMap<String, String> sorted = Maps.newTreeMap();
+        sorted.put("appid", wxCbPayDoc.getAppid());
+        sorted.put("mch_id", wxCbPayDoc.getMchId());
+        sorted.put("out_trade_no", wxCbPayDoc.getOutTradeNo());
+        sorted.put("transaction_id", wxCbPayDoc.getTransactionId());
+        sorted.put("customs", wxCbPayDoc.getCustoms());
+        sorted.put("mch_customs_no", wxCbPayDoc.getMchCustomsNo());
+
+        //2.生成签名
+        StringBuilder sb = new StringBuilder();
+        for (Map.Entry<String,String> entry : sorted.entrySet()) {
+            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
+        }
+        sb.append("key").append("=").append("ZC4g5ryxTQelj3x556HwljSpSX4Enzsy");
+        //签名MD5 加密
+        String sign = DigestUtils.md5Hex(sb.toString()).toUpperCase();
+
+        sorted.put("sign", sign);
+
+        String xml = XmlUtils.map2Xml(sorted);
+
+        //通过http post请求 发送xml数据
+        Request request = OkHttpUtils.buildRequest("https://api.mch.weixin.qq.com/cgi-bin/mch/customs/customdeclareorder",
+                RequestBody.create(MediaType.parse("application/xml; charset=utf-8"), xml));
+        String result = null;
+        try {
+            result = OkHttpUtils.post(request);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+
+
+        StringReader reader = new StringReader(result);
+
+        WxResponseMsg wxResponseMsg = JAXB.unmarshal(reader, WxResponseMsg.class);
+
+        System.out.println(wxResponseMsg);
+    }
+}

+ 22 - 0
src/main/java/com/emato/cuspay/dto/WxResponseMsg.java

@@ -41,6 +41,28 @@ public class WxResponseMsg {
 	//订购人和支付人 校验结果
 	private String certCheckResult;
 
+	@Override
+	public String toString() {
+		return "WxResponseMsg{" +
+				"returnCode='" + returnCode + '\'' +
+				", returnMsg='" + returnMsg + '\'' +
+				", signType='" + signType + '\'' +
+				", sign='" + sign + '\'' +
+				", appid='" + appid + '\'' +
+				", mchId='" + mchId + '\'' +
+				", resultCode='" + resultCode + '\'' +
+				", errCode='" + errCode + '\'' +
+				", errCodeDes='" + errCodeDes + '\'' +
+				", state='" + state + '\'' +
+				", transactionId='" + transactionId + '\'' +
+				", outTradeNo='" + outTradeNo + '\'' +
+				", subOrderNo='" + subOrderNo + '\'' +
+				", subOrderId='" + subOrderId + '\'' +
+				", modifyTime='" + modifyTime + '\'' +
+				", certCheckResult='" + certCheckResult + '\'' +
+				'}';
+	}
+
 	@XmlElement(name = "return_code")
 	public String getReturnCode() {
 		return returnCode;

+ 17 - 0
src/main/java/com/emato/cuspay/notify/AbstractMerchantNotice.java

@@ -0,0 +1,17 @@
+package com.emato.cuspay.notify;
+
+import com.emato.cuspay.dao.data.MerchCusCfg;
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+
+/**
+ * @author zx
+ * @version 1.0
+ * 2018-05-18 10:12
+ */
+public abstract class AbstractMerchantNotice implements MerchantNotice{
+
+
+
+}

+ 29 - 2
src/main/java/com/emato/cuspay/notify/WxMerchantNotice.java

@@ -1,22 +1,49 @@
 package com.emato.cuspay.notify;
 
+import com.emato.cuspay.dao.data.MerchNoti;
+import com.emato.cuspay.dao.mapper.MerchNotiMapper;
+import com.emato.cuspay.dao.mapper.wx.WxCbPayDocMapper;
+import com.google.common.collect.Lists;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
 
 /**
  * @author zengjun
  * @version 1.0
  * 2018-05-18 09:44
  */
-public class WxMerchantNotice implements MerchantNotice{
+
+@Component
+public class WxMerchantNotice extends AbstractMerchantNotice implements MerchantNotice{
 
     private static final Logger logger = LoggerFactory.getLogger(WxMerchantNotice.class);
 
-    @Value("${db.wx.limit}")
+    @Value("${db.wx.notify.limit}")
     private Integer limit;
 
+    @Autowired
+    private MerchNotiMapper merchNotiMapper;
+
     public void notifyMerchant() {
+        limit = (limit != null && limit > 0) ? limit : 20;
+        List<MerchNoti> notis = merchNotiMapper.selectMerchNotis(limit);
+
+        if (notis == null || notis.isEmpty()) {
+            logger.info("no ");
+        }
+
+        //记录异常通知
+        List<MerchNoti> errorsList = Lists.newArrayList();
+
+        notis.forEach(noti->{
+
+        });
+
 
     }
 }

+ 1 - 1
src/main/java/com/emato/cuspay/service/wx/imp/CustomServiceImp.java

@@ -83,7 +83,7 @@ public class CustomServiceImp implements CusPayService {
 
     public void declarePayment() {
         //获取待申报的支付单
-        List<WxCbPayDoc> wxCbPayDocs = wxCbPayDocMapper.selectBeDeclared();
+        List<WxCbPayDoc> wxCbPayDocs = wxCbPayDocMapper.selectBeDeclaredData(20);
         if (wxCbPayDocs == null || wxCbPayDocs.isEmpty()) {
             logger.info("没有待申报微信推海关的支付数据");
             return;

+ 8 - 1
src/main/java/com/emato/cuspay/task/wx/WxCusTimer.java

@@ -1,5 +1,7 @@
 package com.emato.cuspay.task.wx;
 
+import com.emato.cuspay.declare.CusDeclare;
+import com.emato.cuspay.notify.MerchantNotice;
 import com.emato.cuspay.service.MerchNotify;
 import com.emato.cuspay.service.wx.CusPayService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -21,6 +23,11 @@ public class WxCusTimer {
 
     private MerchNotify merchNotify;
 
+    @Autowired
+    private CusDeclare cusDeclare;
+
+    @Autowired
+    private MerchantNotice merchantNotice;
     /**
      * 支付申报定时任务
      */
@@ -34,6 +41,6 @@ public class WxCusTimer {
      */
     @Scheduled(fixedRate = 10000)
     public void notifyTask() {
-
+        cusDeclare.declare();
     }
 }

+ 2 - 2
src/main/resources/mybatis/mapper/wx/WxCbPayDocMapper.xml

@@ -436,11 +436,11 @@
   </update>
 
 
-  <select id="selectBeDeclared" resultMap="BaseResultMap">
+  <select id="selectBeDeclaredData" resultMap="BaseResultMap" parameterType="java.lang.Integer">
     select
     <include refid="Base_Column_List" />
     from wx_cb_pay_doc
-    where doc_status = '00' limit 20
+    where doc_status = '00' limit #{limit}
   </select>
   
   <select id="selectNotify" resultMap="BaseResultMap" parameterType="java.lang.Integer">