1
0
Переглянути джерело

线下订单微信付款和商户管理

zhang 6 роки тому
батько
коміт
ca451060dd
30 змінених файлів з 2809 додано та 221 видалено
  1. 28 1
      README.md
  2. 106 0
      kmall-admin/src/main/java/com/kmall/admin/controller/MerchController.java
  3. 168 47
      kmall-admin/src/main/java/com/kmall/admin/controller/OrderController.java
  4. 16 0
      kmall-admin/src/main/java/com/kmall/admin/dao/MerchDao.java
  5. 20 0
      kmall-admin/src/main/java/com/kmall/admin/dao/OrderWXPayRecordDao.java
  6. 263 0
      kmall-admin/src/main/java/com/kmall/admin/entity/MerchEntity.java
  7. 15 1
      kmall-admin/src/main/java/com/kmall/admin/entity/OrderEntity.java
  8. 241 0
      kmall-admin/src/main/java/com/kmall/admin/entity/OrderWXPayRecordEntity.java
  9. 72 0
      kmall-admin/src/main/java/com/kmall/admin/service/MerchService.java
  10. 65 0
      kmall-admin/src/main/java/com/kmall/admin/service/OrderWXPayRecordService.java
  11. 59 0
      kmall-admin/src/main/java/com/kmall/admin/service/impl/MerchServiceImpl.java
  12. 114 0
      kmall-admin/src/main/java/com/kmall/admin/service/impl/OrderWXPayRecordServiceImpl.java
  13. 4 0
      kmall-admin/src/main/resources/conf/wx-mp.properties
  14. 149 0
      kmall-admin/src/main/resources/mybatis/mapper/MerchDao.xml
  15. 118 0
      kmall-admin/src/main/resources/mybatis/mapper/OrderWXPayRecordDao.xml
  16. 76 0
      kmall-admin/src/main/webapp/WEB-INF/page/shop/merch.html
  17. 27 1
      kmall-admin/src/main/webapp/WEB-INF/page/shop/offilineOrderList.html
  18. 161 0
      kmall-admin/src/main/webapp/js/shop/merch.js
  19. 93 1
      kmall-admin/src/main/webapp/js/shop/offilineOrderList.js
  20. 18 0
      kmall-api/src/main/java/com/kmall/api/service/pay/wxpay/WxPayProperties.java
  21. 18 0
      kmall-common/src/main/java/com/kmall/common/service/pay/wxpay/CommonWxPayProperties.java
  22. 258 0
      kmall-common/src/main/java/com/kmall/common/utils/wechat/WechatMicropayApiResult.java
  23. 38 0
      kmall-common/src/main/java/com/kmall/common/utils/wechat/WechatRefundApiResult.java
  24. 97 0
      kmall-common/src/main/java/com/kmall/common/utils/wechat/WechatReverseApiResult.java
  25. 307 102
      kmall-common/src/main/java/com/kmall/common/utils/wechat/WechatUtil.java
  26. 34 0
      kmall-schedule/src/main/java/com/kmall/schedule/dao/OrderWXPayRecordMapper.java
  27. 8 0
      kmall-schedule/src/main/java/com/kmall/schedule/dao/QzOrderMapper.java
  28. 183 68
      kmall-schedule/src/main/java/com/kmall/schedule/service/QzOrderService.java
  29. 46 0
      kmall-schedule/src/main/resources/mybatis/mapper/OrderWXPayRecordMapper.xml
  30. 7 0
      kmall-schedule/src/main/resources/mybatis/mapper/QzOrderMapper.xml

+ 28 - 1
README.md

@@ -67,7 +67,34 @@ kmall-pt
     * mvn clean
     * mvn package -P prod
     
-## 打印机静默设置
+## 打印机设置
+* 360急速浏览器
+    * 打开浏览器,点击右上角"自定义和控制360急速浏览器"图标,在弹出层上面点击【打印】
+    * 选择打印机
+    * 打开更多设置
+    * 纸张尺寸:选择自定义的选项,如没有,选择默认
+    * 边距:最小
+    * 选项:去掉所有勾选
+    * 此配置为推荐配置,可按实际情况调整
+* 谷歌浏览器
+    * 打开浏览器,点击右上角"自定义及控制Google Chrome"图标,在弹出层上面点击【打印】
+    * 选择打印机
+    * 打开更多设置
+    * 纸张尺寸:选择自定义的选项,如没有,选择默认
+    * 边距:最小
+    * 选项:去掉所有勾选
+    * 此配置为推荐配置,可按实际情况调整
+* 火狐浏览器
+    * 打开浏览器,点击右上角"打开菜单"图标,在弹出层上面点击【打印】
+    * 在新界面左上角点击【打印(p)】
+    * 在弹出层上选择打印机后,点击【确认】
+    * 在新界面左上角点击【页面设置(U)】
+    * 在弹出层上点击【页边距和页眉/页脚】
+    * 在"页边距"中左右顶底都设置为0.1
+    * 在"页眉和页脚"中所有选项都选择空白
+    * 点击【确认】->点击【关闭】完成配置
+    * 此配置为推荐配置,可按实际情况调整
+#### 打印机静默设置
 * 谷歌浏览器
     * 第一次打印设置好打印样式
     * 右键快捷方式,点击【属性】,在【目标】尾部位置添加“ --kiosk-printing”注意空格,

+ 106 - 0
kmall-admin/src/main/java/com/kmall/admin/controller/MerchController.java

@@ -0,0 +1,106 @@
+package com.kmall.admin.controller;
+
+import java.util.List;
+import java.util.Map;
+
+import com.kmall.admin.entity.MerchEntity;
+import com.kmall.admin.service.MerchService;
+import com.kmall.common.utils.PageUtils;
+import com.kmall.common.utils.Query;
+import com.kmall.common.utils.R;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * Controller
+ *
+ * @author emato
+ * @email admin@qhdswl.com
+ * @date 2018-12-06 09:41:34
+ */
+@Controller
+@RequestMapping("merch")
+public class MerchController {
+    @Autowired
+    private MerchService merchService;
+
+    /**
+     * 查看列表
+     */
+    @RequestMapping("/list")
+    @RequiresPermissions("merch:list")
+    @ResponseBody
+    public R list(@RequestParam Map<String, Object> params) {
+        //查询列表数据
+        Query query = new Query(params);
+
+        List<MerchEntity> merchList = merchService.queryList(query);
+        int total = merchService.queryTotal(query);
+
+        PageUtils pageUtil = new PageUtils(merchList, total, query.getLimit(), query.getPage());
+
+        return R.ok().put("page", pageUtil);
+    }
+
+    /**
+     * 查看信息
+     */
+    @RequestMapping("/info/{id}")
+    @RequiresPermissions("merch:info")
+    @ResponseBody
+    public R info(@PathVariable("id") Integer id) {
+        MerchEntity merch = merchService.queryObject(id);
+
+        return R.ok().put("merch", merch);
+    }
+
+    /**
+     * 保存
+     */
+    @RequestMapping("/save")
+    @RequiresPermissions("merch:save")
+    @ResponseBody
+    public R save(@RequestBody MerchEntity merch) {
+        merchService.save(merch);
+
+        return R.ok();
+    }
+
+    /**
+     * 修改
+     */
+    @RequestMapping("/update")
+    @RequiresPermissions("merch:update")
+    @ResponseBody
+    public R update(@RequestBody MerchEntity merch) {
+        merchService.update(merch);
+
+        return R.ok();
+    }
+
+    /**
+     * 删除
+     */
+    @RequestMapping("/delete")
+    @RequiresPermissions("merch:delete")
+    @ResponseBody
+    public R delete(@RequestBody Integer[] ids) {
+        merchService.deleteBatch(ids);
+
+        return R.ok();
+    }
+
+    /**
+     * 查看所有列表
+     */
+    @RequestMapping("/queryAll")
+    @ResponseBody
+    public R queryAll(@RequestParam Map<String, Object> params) {
+
+        List<MerchEntity> list = merchService.queryList(params);
+
+        return R.ok().put("list", list);
+    }
+}

+ 168 - 47
kmall-admin/src/main/java/com/kmall/admin/controller/OrderController.java

@@ -9,7 +9,9 @@ import com.kmall.api.contants.Dict;
 import com.kmall.common.entity.SysUserEntity;
 import com.kmall.common.utils.*;
 import com.kmall.common.utils.print.ticket.item.Ticket;
+import com.kmall.common.utils.wechat.WechatMicropayApiResult;
 import com.kmall.common.utils.wechat.WechatRefundApiResult;
+import com.kmall.common.utils.wechat.WechatReverseApiResult;
 import com.kmall.common.utils.wechat.WechatUtil;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -38,6 +40,10 @@ public class OrderController {
     private OrderRefundService orderRefundService;
     @Autowired
     private OrderExceptionRecordService orderExceptionRecordService;
+    @Autowired
+    private StoreService storeService;
+    @Autowired
+    private OrderWXPayRecordService orderWXPayRecordService;
 
     /**
      * 列表
@@ -46,14 +52,14 @@ public class OrderController {
     @RequiresPermissions("order:list")
     public R list(@RequestParam Map<String, Object> params) {
         SysUserEntity user = ShiroUtils.getUserEntity();
-        if(user != null) {
+        if (user != null) {
             if (user.getRoleType().equalsIgnoreCase("2")) {
                 params.put("storeId", user.getStoreId());
             }
         }
         //查询列表数据
         Query query = new Query(params);
-        query.put("isOnfiilineOrder",Dict.isOnfflineOrder.item_0.getItem());
+        query.put("isOnfiilineOrder", Dict.isOnfflineOrder.item_0.getItem());
         List<OrderEntity> orderList = orderService.queryList(query);
         int total = orderService.queryTotal(query);
 
@@ -166,6 +172,7 @@ public class OrderController {
 
     /**
      * 跟踪快递轨迹
+     *
      * @param id
      * @return
      */
@@ -178,6 +185,7 @@ public class OrderController {
 
     /**
      * 获取订单清关信息
+     *
      * @param orderSn
      * @return
      */
@@ -185,48 +193,62 @@ public class OrderController {
     @RequiresPermissions("order:getProcess")
     public R getProcess(@PathVariable("orderSn") String orderSn) {
         OrderProcessRecordEntity orderProcessRecordEntity = orderProcessRecordService.queryObjectByOrderSn(orderSn);
-        if(orderProcessRecordEntity != null){
-            if(orderProcessRecordEntity.getShipmentStartTime()!=null){
-                orderProcessRecordEntity.setShipmentStartTimeStr(DateUtils.format(orderProcessRecordEntity.getShipmentStartTime(),DateUtils.DATE_TIME_PATTERN));
+        if (orderProcessRecordEntity != null) {
+            if (orderProcessRecordEntity.getShipmentStartTime() != null) {
+                orderProcessRecordEntity.setShipmentStartTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getShipmentStartTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getShipmentSuccTime()!=null){
-                orderProcessRecordEntity.setShipmentSuccTimeStr(DateUtils.format(orderProcessRecordEntity.getShipmentSuccTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getShipmentSuccTime() != null) {
+                orderProcessRecordEntity.setShipmentSuccTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getShipmentSuccTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getCustomsStartTime()!=null){
-                orderProcessRecordEntity.setCustomsStartTimeStr(DateUtils.format(orderProcessRecordEntity.getCustomsStartTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getCustomsStartTime() != null) {
+                orderProcessRecordEntity.setCustomsStartTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getCustomsStartTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getCustomsSuccTime()!=null){
-                orderProcessRecordEntity.setCustomsSuccTimeStr(DateUtils.format(orderProcessRecordEntity.getCustomsSuccTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getCustomsSuccTime() != null) {
+                orderProcessRecordEntity.setCustomsSuccTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getCustomsSuccTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getWaybillStartTime()!=null){
-                orderProcessRecordEntity.setWaybillStartTimeStr(DateUtils.format(orderProcessRecordEntity.getWaybillStartTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getWaybillStartTime() != null) {
+                orderProcessRecordEntity.setWaybillStartTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getWaybillStartTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getWaybillSuccTime()!=null){
-                orderProcessRecordEntity.setWaybillSuccTimeStr(DateUtils.format(orderProcessRecordEntity.getWaybillSuccTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getWaybillSuccTime() != null) {
+                orderProcessRecordEntity.setWaybillSuccTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getWaybillSuccTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getEleOrderStartTime()!=null){
-                orderProcessRecordEntity.setEleOrderStartTimeStr(DateUtils.format(orderProcessRecordEntity.getEleOrderStartTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getEleOrderStartTime() != null) {
+                orderProcessRecordEntity.setEleOrderStartTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getEleOrderStartTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getEleOrderSuccTime()!=null){
-                orderProcessRecordEntity.setEleOrderSuccTimeStr(DateUtils.format(orderProcessRecordEntity.getEleOrderSuccTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getEleOrderSuccTime() != null) {
+                orderProcessRecordEntity.setEleOrderSuccTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getEleOrderSuccTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getAddOrderStartTime()!=null){
-                orderProcessRecordEntity.setAddOrderStartTimeStr(DateUtils.format(orderProcessRecordEntity.getAddOrderStartTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getAddOrderStartTime() != null) {
+                orderProcessRecordEntity.setAddOrderStartTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getAddOrderStartTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getAddOrderSuccTime()!=null){
-                orderProcessRecordEntity.setAddOrderSuccTimeStr(DateUtils.format(orderProcessRecordEntity.getAddOrderSuccTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getAddOrderSuccTime() != null) {
+                orderProcessRecordEntity.setAddOrderSuccTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getAddOrderSuccTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getPaySuccTime()!=null){
-                orderProcessRecordEntity.setPaySuccTimeStr(DateUtils.format(orderProcessRecordEntity.getPaySuccTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getPaySuccTime() != null) {
+                orderProcessRecordEntity.setPaySuccTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getPaySuccTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getPayStartTime()!=null){
-                orderProcessRecordEntity.setPayStartTimeStr(DateUtils.format(orderProcessRecordEntity.getPayStartTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getPayStartTime() != null) {
+                orderProcessRecordEntity.setPayStartTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getPayStartTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getPaymentStartTime()!=null){
-                orderProcessRecordEntity.setPaymentStartTimeStr(DateUtils.format(orderProcessRecordEntity.getPaymentStartTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getPaymentStartTime() != null) {
+                orderProcessRecordEntity.setPaymentStartTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getPaymentStartTime(), DateUtils.DATE_TIME_PATTERN));
             }
-            if(orderProcessRecordEntity.getPaymentSuccTime()!=null){
-                orderProcessRecordEntity.setPaymentSuccTimeStr(DateUtils.format(orderProcessRecordEntity.getPaymentSuccTime(),DateUtils.DATE_TIME_PATTERN));
+            if (orderProcessRecordEntity.getPaymentSuccTime() != null) {
+                orderProcessRecordEntity.setPaymentSuccTimeStr(
+                        DateUtils.format(orderProcessRecordEntity.getPaymentSuccTime(), DateUtils.DATE_TIME_PATTERN));
             }
         }
         return R.ok().put("orderProcessRecordEntity", orderProcessRecordEntity);
@@ -273,24 +295,24 @@ public class OrderController {
         if (null == orderInfo) {
             return R.error("订单不存在");
         }
-        if (orderInfo.getOrderStatus() == Integer.parseInt(Dict.orderStatus.item_401.getItem())
-                || orderInfo.getOrderStatus() == Integer.parseInt(Dict.orderStatus.item_402.getItem())) {
+        if (orderInfo.getOrderStatus() == Integer.parseInt(Dict.orderStatus.item_401.getItem()) ||
+            orderInfo.getOrderStatus() == Integer.parseInt(Dict.orderStatus.item_402.getItem())) {
             return R.error("订单已退款");
         }
         Double totalActualPrice = orderService.getTotalActualPrice(orderInfo.getMerchOrderSn());
-        if(totalActualPrice == null){
+        if (totalActualPrice == null) {
             totalActualPrice = 0d;
         }
 
         if (orderInfo.getOrderStatus() != 0) {
             // todo 退款
-//          WechatRefundApiResult result = WechatUtil.wxRefund(orderInfo.getOrderSn().toString(),
-//          orderInfo.getActualPrice().doubleValue(), refundMoney.doubleValue());
-            WechatRefundApiResult result = WechatUtil.wxRefund(orderInfo.getMerchOrderSn().toString(),
-                    totalActualPrice, orderInfo.getActualPrice().doubleValue());
+            //          WechatRefundApiResult result = WechatUtil.wxRefund(orderInfo.getOrderSn().toString(),
+            //          orderInfo.getActualPrice().doubleValue(), refundMoney.doubleValue());
+            WechatRefundApiResult result = WechatUtil.wxRefund(orderInfo.getMerchOrderSn().toString(), totalActualPrice,
+                                                               orderInfo.getActualPrice().doubleValue());
             if (result.getResult_code().equals("SUCCESS")) {
-                orderService.refund(orderInfo,result);
-            }else{
+                orderService.refund(orderInfo, result);
+            } else {
                 OrderRefundEntity mallOrderRefund = orderRefundService.queryObjectByOrderId(orderInfo.getId());
                 OrderRefundEntity orderRefund = new OrderRefundEntity();
                 orderRefund.setRefundType(Integer.parseInt(Dict.RefundType.item_1.getItem()));
@@ -298,16 +320,16 @@ public class OrderController {
                 orderRefund.setRefundStatus(Integer.parseInt(Dict.RefundStatus.item_4.getItem()));
                 orderRefund.setModTime(new Date());
                 orderRefund.setOutRefundNo(result.getOut_refund_no());
-                if(mallOrderRefund !=null){
+                if (mallOrderRefund != null) {
                     orderRefund.setId(mallOrderRefund.getId());
                     orderRefundService.update(orderRefund);//退款记录
                 }
 
                 OrderExceptionRecordEntity mallOrderExceptionRecord = new OrderExceptionRecordEntity();
-                mallOrderExceptionRecord.setUserId(Integer.parseInt(orderInfo.getUserId()+""));
+                mallOrderExceptionRecord.setUserId(Integer.parseInt(orderInfo.getUserId() + ""));
                 mallOrderExceptionRecord.setOrderSn(orderInfo.getOrderSn());
                 mallOrderExceptionRecord.setExceptionStatus(Dict.exceptionStatus.item_03.getItem());
-                mallOrderExceptionRecord.setExceptionContent("退款失败"+result.getErr_code_des());
+                mallOrderExceptionRecord.setExceptionContent("退款失败" + result.getErr_code_des());
                 mallOrderExceptionRecord.setCreateTime(new Date());
                 orderExceptionRecordService.save(mallOrderExceptionRecord);
 
@@ -320,6 +342,7 @@ public class OrderController {
 
     /**
      * 获取首页展示信息--会员购买率相关
+     *
      * @param params
      * @return
      */
@@ -337,9 +360,9 @@ public class OrderController {
         Map resultObj = null;
         try {
             SysUserEntity user = ShiroUtils.getUserEntity();
-            resultObj = orderService.orderSubmit(offlineCartEntityList,user);
+            resultObj = orderService.orderSubmit(offlineCartEntityList, user);
             if (null != resultObj) {
-                return R.error((String)resultObj.get("errmsg"));
+                return R.error((String) resultObj.get("errmsg"));
             }
         } catch (Exception e) {
             e.printStackTrace();
@@ -349,6 +372,7 @@ public class OrderController {
 
     /**
      * 确认付款
+     *
      * @param id
      * @return
      */
@@ -364,14 +388,14 @@ public class OrderController {
     @RequiresPermissions("order:offilineOrderList")
     public R offilineOrderList(@RequestParam Map<String, Object> params) {
         SysUserEntity user = ShiroUtils.getUserEntity();
-        if(user != null) {
+        if (user != null) {
             if (user.getRoleType().equalsIgnoreCase("2")) {
                 params.put("storeId", user.getStoreId());
             }
         }
         //查询列表数据
         Query query = new Query(params);
-        query.put("isOnfiilineOrder",Dict.isOnfflineOrder.item_1.getItem());
+        query.put("isOnfiilineOrder", Dict.isOnfflineOrder.item_1.getItem());
         List<OrderEntity> orderList = orderService.queryOffilineOrderList(query);
         int total = orderService.queryTotal(query);
 
@@ -384,6 +408,103 @@ public class OrderController {
     @RequiresPermissions("order:offlineInfos")
     public R queryObjectBySysUser(@PathVariable("id") Long id) {
         OrderEntity order = orderService.queryObjectBySysUser(id);
+        List<OrderWXPayRecordEntity> payRecords = orderWXPayRecordService.getRecordsByOutTradeNo(order.getOrderSn());
+        order.setPayRecordList(payRecords);
         return R.ok().put("order", order);
     }
+
+
+    @RequestMapping("/wxMicropayPay")
+    @RequiresPermissions("order:wxMicropayPay")
+    public R wxMicropayPay(Long id, String auth_code) {
+        R r = null;
+        SysUserEntity user = ShiroUtils.getUserEntity();
+        if (user == null) {
+            throw new RRException("用户登录超时,请重新登录");
+        }
+        if (!user.getRoleType().equalsIgnoreCase("2")) {
+            throw new RRException("该操作只允许店员账户操作");
+        }
+        OrderEntity orderEntity = orderService.queryObject(id);
+        if (orderEntity.getOrderStatus() == Integer.valueOf(Dict.orderStatus.item_201.getItem())) {
+            throw new RRException("此订单已付款!");
+        }
+        if (orderEntity.getOrderStatus() == Integer.valueOf(Dict.orderStatus.item_301.getItem())) {
+            throw new RRException("此订单已完成!");
+        }
+        if (orderEntity.getOrderStatus() == Integer.valueOf(Dict.orderStatus.item_101.getItem())) {
+            throw new RRException("此订单已取消!");
+        }
+        if (orderEntity.getOrderStatus() == Integer.valueOf(Dict.orderStatus.item_102.getItem())) {
+            throw new RRException("此订单已删除!");
+        }
+
+        //保存支付记录
+        OrderWXPayRecordEntity orderWXPayRecordCurrent = orderWXPayRecordService.saveRecord(orderEntity);
+
+        StoreEntity store = storeService.queryObject(orderEntity.getStoreId());
+        WechatMicropayApiResult wechatMicropayApiResult = WechatUtil
+                .wxMicropay(store.getMerchName() + "-" + store.getStoreName(), orderEntity.getOrderBizType(), null,
+                            orderWXPayRecordCurrent.getOutTradeNoWX(), orderEntity.getActualPrice().doubleValue(),
+                            "127.0.0.1", auth_code);
+        System.out.println("orderWXPayRecordEntity.id=" + orderWXPayRecordCurrent.getId());
+        orderWXPayRecordService.updateRecord(orderWXPayRecordCurrent.getId(), wechatMicropayApiResult);
+        System.out.println(wechatMicropayApiResult);
+
+        //当支付成功时,修改订单,并把其他支付记录撤销
+        if (WechatUtil.WXTradeState.SUCCESS.getCode().equals(wechatMicropayApiResult.getTrade_state())) {
+            //查询当前订单所有的支付记录
+            List<OrderWXPayRecordEntity> orderWXPayRecordEntitys =
+                    orderWXPayRecordService.getRecordsByOutTradeNo(orderEntity.getOrderSn());
+            for (OrderWXPayRecordEntity orderWXPayRecordTemp : orderWXPayRecordEntitys) {
+                //查询出来的记录不等于当前记录,并且未撤销,未关闭时,撤销订单
+                if (orderWXPayRecordTemp.getId() != orderWXPayRecordCurrent.getId() &&
+                    (!WechatUtil.WXTradeState.REVOKED.getCode().equals(orderWXPayRecordTemp.getTradeState()) ||
+                     !WechatUtil.WXTradeState.CLOSED.getCode().equals(orderWXPayRecordTemp.getTradeState()))) {
+                    WechatReverseApiResult wechatReverseApiResult =
+                            WechatUtil.wxReverse(orderWXPayRecordTemp.getOutTradeNoWX());
+                    //撤销订单成功
+                    if ("SUCCESS".equals(wechatReverseApiResult.getReturn_code()) &&
+                        "SUCCESS".equals(wechatReverseApiResult.getResult_code())) {
+                        //调用订单查询接口
+                        WechatRefundApiResult wechatRefundApiResult =
+                                WechatUtil.wxOrderQuery(orderWXPayRecordTemp.getOutTradeNoWX());
+                        if ("SUCCESS".equals(wechatRefundApiResult.getReturn_code()) &&
+                            "SUCCESS".equals(wechatRefundApiResult.getResult_code())) {
+                            // 修改订单支付记录
+                            orderWXPayRecordService
+                                    .updateWXPayRecordTradeState(orderWXPayRecordTemp.getId(), wechatRefundApiResult);
+                        }
+                    }
+                }
+            }
+            orderService.confirmPay(id);
+            r = R.ok();
+            //用户支付中
+        } else if (WechatUtil.WXTradeState.USERPAYING.getCode().equals(wechatMicropayApiResult.getTrade_state())) {
+            r = R.error(WechatUtil.WXTradeState.USERPAYING.getCodeZn() + ",稍等片刻后请刷新页面重新查看订单状态");
+            //用户支付失败
+        } else if (WechatUtil.WXTradeState.PAYERROR.getCode().equals(wechatMicropayApiResult.getTrade_state())) {
+            WechatReverseApiResult wechatReverseApiResult =
+                    WechatUtil.wxReverse(orderWXPayRecordCurrent.getOutTradeNoWX());
+            //撤销订单成功
+            if ("SUCCESS".equals(wechatReverseApiResult.getReturn_code()) &&
+                "SUCCESS".equals(wechatReverseApiResult.getResult_code())) {
+                //调用订单查询接口
+                WechatRefundApiResult wechatRefundApiResult =
+                        WechatUtil.wxOrderQuery(orderWXPayRecordCurrent.getOutTradeNoWX());
+                if ("SUCCESS".equals(wechatRefundApiResult.getReturn_code()) &&
+                    "SUCCESS".equals(wechatRefundApiResult.getResult_code())) {
+                    // 修改订单支付记录
+                    orderWXPayRecordService
+                            .updateWXPayRecordTradeState(orderWXPayRecordCurrent.getId(), wechatRefundApiResult);
+                }
+                r = R.error(orderWXPayRecordCurrent.getErrCodeDes());
+            } else {
+                r = R.error(wechatReverseApiResult.getErr_code_des());
+            }
+
+        }
+        return r;
+    }
 }

+ 16 - 0
kmall-admin/src/main/java/com/kmall/admin/dao/MerchDao.java

@@ -0,0 +1,16 @@
+package com.kmall.admin.dao;
+
+import com.kmall.admin.entity.MerchEntity;
+import com.kmall.common.dao.BaseDao;
+
+/**
+ * Dao
+ *
+ * @author emato
+ * @email admin@qhdswl.com
+ * @date 2018-12-06 09:41:34
+ */
+public interface MerchDao
+        extends BaseDao<MerchEntity> {
+
+}

+ 20 - 0
kmall-admin/src/main/java/com/kmall/admin/dao/OrderWXPayRecordDao.java

@@ -0,0 +1,20 @@
+package com.kmall.admin.dao;
+
+
+import com.kmall.admin.entity.OrderWXPayRecordEntity;
+import com.kmall.common.dao.BaseDao;
+
+import java.util.List;
+
+/**
+ * 微信付款码支付记录Dao
+ */
+public interface OrderWXPayRecordDao extends BaseDao<OrderWXPayRecordEntity> {
+
+    OrderWXPayRecordEntity findByOutTradeNoWX(String outTradeNoWX);
+
+    int countByOutTradeNo(String outTradeNo);
+
+    List<OrderWXPayRecordEntity> getRecordByOutTradeNo(String outTradeNo);
+
+}

+ 263 - 0
kmall-admin/src/main/java/com/kmall/admin/entity/MerchEntity.java

@@ -0,0 +1,263 @@
+package com.kmall.admin.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 实体
+ * 表名 mall_merch
+ *
+ * @author emato
+ * @email admin@qhdswl.com
+ * @date 2018-12-06 09:41:34
+ */
+public class MerchEntity
+        implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    private Integer id;
+    /**
+     * 商户编号
+     */
+    private String merchSn;
+    /**
+     * 商户名称
+     */
+    private String merchName;
+    /**
+     * 商户简称
+     */
+    private String merchShortName;
+    /**
+     * 商户图片
+     */
+    private String merchImg;
+    /**
+     * 排序
+     */
+    private Integer sortOrder;
+    /**
+     * 是否显示
+     */
+    private Integer isShow;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 创建人编号
+     */
+    private String createrSn;
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+    /**
+     * 修改人编号
+     */
+    private String moderSn;
+    /**
+     * 修改时间
+     */
+    private Date modTime;
+    /**
+     * 时间戳
+     */
+    private Date tstm;
+
+    //翻译用字段
+    private String show;
+
+    public String getShow() {
+        return show;
+    }
+
+    public void setShow(String show) {
+        this.show = show;
+    }
+
+    /**
+     * 设置:主键
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * 获取:主键
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * 设置:商户编号
+     */
+    public void setMerchSn(String merchSn) {
+        this.merchSn = merchSn;
+    }
+
+    /**
+     * 获取:商户编号
+     */
+    public String getMerchSn() {
+        return merchSn;
+    }
+
+    /**
+     * 设置:商户名称
+     */
+    public void setMerchName(String merchName) {
+        this.merchName = merchName;
+    }
+
+    /**
+     * 获取:商户名称
+     */
+    public String getMerchName() {
+        return merchName;
+    }
+
+    /**
+     * 设置:商户简称
+     */
+    public void setMerchShortName(String merchShortName) {
+        this.merchShortName = merchShortName;
+    }
+
+    /**
+     * 获取:商户简称
+     */
+    public String getMerchShortName() {
+        return merchShortName;
+    }
+
+    /**
+     * 设置:商户图片
+     */
+    public void setMerchImg(String merchImg) {
+        this.merchImg = merchImg;
+    }
+
+    /**
+     * 获取:商户图片
+     */
+    public String getMerchImg() {
+        return merchImg;
+    }
+
+    /**
+     * 设置:排序
+     */
+    public void setSortOrder(Integer sortOrder) {
+        this.sortOrder = sortOrder;
+    }
+
+    /**
+     * 获取:排序
+     */
+    public Integer getSortOrder() {
+        return sortOrder;
+    }
+
+    /**
+     * 获取:显示
+     */
+    public Integer getIsShow() {
+        return isShow;
+    }
+
+    /**
+     * 设置:显示
+     */
+    public void setIsShow(Integer isShow) {
+        this.isShow = isShow;
+    }
+
+    /**
+     * 设置:备注
+     */
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    /**
+     * 获取:备注
+     */
+    public String getRemark() {
+        return remark;
+    }
+
+    /**
+     * 设置:创建人编号
+     */
+    public void setCreaterSn(String createrSn) {
+        this.createrSn = createrSn;
+    }
+
+    /**
+     * 获取:创建人编号
+     */
+    public String getCreaterSn() {
+        return createrSn;
+    }
+
+    /**
+     * 设置:创建时间
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * 获取:创建时间
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * 设置:修改人编号
+     */
+    public void setModerSn(String moderSn) {
+        this.moderSn = moderSn;
+    }
+
+    /**
+     * 获取:修改人编号
+     */
+    public String getModerSn() {
+        return moderSn;
+    }
+
+    /**
+     * 设置:修改时间
+     */
+    public void setModTime(Date modTime) {
+        this.modTime = modTime;
+    }
+
+    /**
+     * 获取:修改时间
+     */
+    public Date getModTime() {
+        return modTime;
+    }
+
+    /**
+     * 设置:时间戳
+     */
+    public void setTstm(Date tstm) {
+        this.tstm = tstm;
+    }
+
+    /**
+     * 获取:时间戳
+     */
+    public Date getTstm() {
+        return tstm;
+    }
+}

+ 15 - 1
kmall-admin/src/main/java/com/kmall/admin/entity/OrderEntity.java

@@ -13,7 +13,8 @@ import java.util.List;
  * @email
  * @date 2017-08-13 10:41:09
  */
-public class OrderEntity implements Serializable {
+public class OrderEntity
+        implements Serializable {
     private static final long serialVersionUID = 1L;
 
     //主键
@@ -754,4 +755,17 @@ public class OrderEntity implements Serializable {
     public void setOrderGoodsEntityList(List<OrderGoodsEntity> orderGoodsEntityList) {
         this.orderGoodsEntityList = orderGoodsEntityList;
     }
+
+
+    private List<OrderWXPayRecordEntity> payRecordList;
+
+    public List<OrderWXPayRecordEntity> getPayRecordList() {
+        return payRecordList;
+    }
+
+    public void setPayRecordList(List<OrderWXPayRecordEntity> payRecordList) {
+        this.payRecordList = payRecordList;
+    }
+
+
 }

+ 241 - 0
kmall-admin/src/main/java/com/kmall/admin/entity/OrderWXPayRecordEntity.java

@@ -0,0 +1,241 @@
+package com.kmall.admin.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 订单异常记录表实体
+ * 表名 mall_order_exception_record
+ *
+ * @author emato
+ * @email admin@qhdswl.com
+ * @date 2018-10-31 17:15:22
+ */
+public class OrderWXPayRecordEntity
+        implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 编号
+     */
+    private Integer id;
+
+
+    private String returnCode;//返回状态码
+    private String returnMsg;//返回信息
+
+    private String resultCode;//业务结果
+    private String errCode;//错误代码
+    private String errCodeDes;//错误代码描述
+
+
+    private String openid;//用户标识
+    private String isSubscribe;//是否关注公众账号
+    private String tradeType;//交易类型(MICROPAY 付款码支付)
+    private String feeType;//货币类型
+    private String totalFee;//订单金额
+    private String transactionId;//微信支付订单号
+    private String outTradeNo;//商户订单号
+    private String outTradeNoWX;//发送给微信的商户订单号  outTradeNo + "_" + (发送次数-1)
+    private String attach;//商家数据包
+    private String timeEnd;//支付完成时间
+
+    private String tradeState;//交易状态
+
+    /**
+     * 创建人编号
+     */
+    private String createrSn;
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+    /**
+     * 修改人编号
+     */
+    private String moderSn;
+    /**
+     * 修改时间
+     */
+    private Date modTime;
+    /**
+     * 时间戳
+     */
+    private Date tstm;
+
+    public String getOutTradeNoWX() {
+        return outTradeNoWX;
+    }
+
+    public void setOutTradeNoWX(String outTradeNoWX) {
+        this.outTradeNoWX = outTradeNoWX;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getReturnCode() {
+        return returnCode;
+    }
+
+    public void setReturnCode(String returnCode) {
+        this.returnCode = returnCode;
+    }
+
+    public String getReturnMsg() {
+        return returnMsg;
+    }
+
+    public void setReturnMsg(String returnMsg) {
+        this.returnMsg = returnMsg;
+    }
+
+    public String getResultCode() {
+        return resultCode;
+    }
+
+    public void setResultCode(String resultCode) {
+        this.resultCode = resultCode;
+    }
+
+    public String getErrCode() {
+        return errCode;
+    }
+
+    public void setErrCode(String errCode) {
+        this.errCode = errCode;
+    }
+
+    public String getErrCodeDes() {
+        return errCodeDes;
+    }
+
+    public void setErrCodeDes(String errCodeDes) {
+        this.errCodeDes = errCodeDes;
+    }
+
+    public String getOpenid() {
+        return openid;
+    }
+
+    public void setOpenid(String openid) {
+        this.openid = openid;
+    }
+
+    public String getIsSubscribe() {
+        return isSubscribe;
+    }
+
+    public void setIsSubscribe(String isSubscribe) {
+        this.isSubscribe = isSubscribe;
+    }
+
+    public String getTradeType() {
+        return tradeType;
+    }
+
+    public void setTradeType(String tradeType) {
+        this.tradeType = tradeType;
+    }
+
+    public String getFeeType() {
+        return feeType;
+    }
+
+    public void setFeeType(String feeType) {
+        this.feeType = feeType;
+    }
+
+    public String getTotalFee() {
+        return totalFee;
+    }
+
+    public void setTotalFee(String totalFee) {
+        this.totalFee = totalFee;
+    }
+
+    public String getTransactionId() {
+        return transactionId;
+    }
+
+    public void setTransactionId(String transactionId) {
+        this.transactionId = transactionId;
+    }
+
+    public String getOutTradeNo() {
+        return outTradeNo;
+    }
+
+    public void setOutTradeNo(String outTradeNo) {
+        this.outTradeNo = outTradeNo;
+    }
+
+    public String getAttach() {
+        return attach;
+    }
+
+    public void setAttach(String attach) {
+        this.attach = attach;
+    }
+
+    public String getTimeEnd() {
+        return timeEnd;
+    }
+
+    public void setTimeEnd(String timeEnd) {
+        this.timeEnd = timeEnd;
+    }
+
+    public String getTradeState() {
+        return tradeState;
+    }
+
+    public void setTradeState(String tradeState) {
+        this.tradeState = tradeState;
+    }
+
+    public String getCreaterSn() {
+        return createrSn;
+    }
+
+    public void setCreaterSn(String createrSn) {
+        this.createrSn = createrSn;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getModerSn() {
+        return moderSn;
+    }
+
+    public void setModerSn(String moderSn) {
+        this.moderSn = moderSn;
+    }
+
+    public Date getModTime() {
+        return modTime;
+    }
+
+    public void setModTime(Date modTime) {
+        this.modTime = modTime;
+    }
+
+    public Date getTstm() {
+        return tstm;
+    }
+
+    public void setTstm(Date tstm) {
+        this.tstm = tstm;
+    }
+}

+ 72 - 0
kmall-admin/src/main/java/com/kmall/admin/service/MerchService.java

@@ -0,0 +1,72 @@
+package com.kmall.admin.service;
+
+import com.kmall.admin.entity.MerchEntity;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Service接口
+ *
+ * @author emato
+ * @email admin@qhdswl.com
+ * @date 2018-12-06 09:41:34
+ */
+public interface MerchService {
+
+    /**
+     * 根据主键查询实体
+     *
+     * @param id 主键
+     * @return 实体
+     */
+    MerchEntity queryObject(Integer id);
+
+    /**
+     * 分页查询
+     *
+     * @param map 参数
+     * @return list
+     */
+    List<MerchEntity> queryList(Map<String, Object> map);
+
+    /**
+     * 分页统计总数
+     *
+     * @param map 参数
+     * @return 总数
+     */
+    int queryTotal(Map<String, Object> map);
+
+    /**
+     * 保存实体
+     *
+     * @param merch 实体
+     * @return 保存条数
+     */
+    int save(MerchEntity merch);
+
+    /**
+     * 根据主键更新实体
+     *
+     * @param merch 实体
+     * @return 更新条数
+     */
+    int update(MerchEntity merch);
+
+    /**
+     * 根据主键删除
+     *
+     * @param id
+     * @return 删除条数
+     */
+    int delete(Integer id);
+
+    /**
+     * 根据主键批量删除
+     *
+     * @param ids
+     * @return 删除条数
+     */
+    int deleteBatch(Integer[] ids);
+}

+ 65 - 0
kmall-admin/src/main/java/com/kmall/admin/service/OrderWXPayRecordService.java

@@ -0,0 +1,65 @@
+package com.kmall.admin.service;
+
+import com.kmall.admin.entity.OrderEntity;
+import com.kmall.admin.entity.OrderWXPayRecordEntity;
+import com.kmall.common.utils.wechat.WechatMicropayApiResult;
+import com.kmall.common.utils.wechat.WechatRefundApiResult;
+
+import java.util.List;
+
+/**
+ * 微信付款码付款service
+ */
+public interface OrderWXPayRecordService {
+
+    /**
+     * 根据发送给微信的订单编号获取唯一的记录
+     *
+     * @param outTradeNoWX 发送给微信的订单编号(商户订单编号+"_"+(发送次数-1))
+     * @return 唯一的记录
+     */
+    OrderWXPayRecordEntity findByOutTradeNoWX(String outTradeNoWX);
+
+    /**
+     * 获取商户订单发起付款记录次数
+     *
+     * @param outTradeNo 商户订单
+     * @return 发起付款记录次数
+     */
+    int countByOutTradeNo(String outTradeNo);
+
+    /**
+     * 获取商户订单所有的付款记录
+     *
+     * @param outTradeNo 商户订单
+     * @return 所有的付款记录
+     */
+    List<OrderWXPayRecordEntity> getRecordsByOutTradeNo(String outTradeNo);
+
+    /**
+     * 保存记录
+     *
+     * @param order 订单信息
+     * @return 付款记录信息
+     */
+    OrderWXPayRecordEntity saveRecord(OrderEntity order);
+
+    /**
+     * 根据微信返回的信息修改支付记录
+     *
+     * @param id                      支付记录id
+     * @param wechatMicropayApiResult 微信返回的信息
+     * @return 0为成功
+     */
+    int updateRecord(Integer id, WechatMicropayApiResult wechatMicropayApiResult);
+
+
+    /**
+     * 修改支付记录的交易状态
+     *
+     * @param id                    支付记录id
+     * @param wechatRefundApiResult 查询订单返回信息
+     * @return 0为成功
+     */
+    int updateWXPayRecordTradeState(Integer id, WechatRefundApiResult wechatRefundApiResult);
+}

+ 59 - 0
kmall-admin/src/main/java/com/kmall/admin/service/impl/MerchServiceImpl.java

@@ -0,0 +1,59 @@
+package com.kmall.admin.service.impl;
+
+import com.kmall.admin.dao.MerchDao;
+import com.kmall.admin.entity.MerchEntity;
+import com.kmall.admin.service.MerchService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Service实现类
+ *
+ * @author emato
+ * @email admin@qhdswl.com
+ * @date 2018-12-06 09:41:34
+ */
+@Service("merchService")
+public class MerchServiceImpl
+        implements MerchService {
+    @Autowired
+    private MerchDao merchDao;
+
+    @Override
+    public MerchEntity queryObject(Integer id) {
+        return merchDao.queryObject(id);
+    }
+
+    @Override
+    public List<MerchEntity> queryList(Map<String, Object> map) {
+        return merchDao.queryList(map);
+    }
+
+    @Override
+    public int queryTotal(Map<String, Object> map) {
+        return merchDao.queryTotal(map);
+    }
+
+    @Override
+    public int save(MerchEntity merch) {
+        return merchDao.save(merch);
+    }
+
+    @Override
+    public int update(MerchEntity merch) {
+        return merchDao.update(merch);
+    }
+
+    @Override
+    public int delete(Integer id) {
+        return merchDao.delete(id);
+    }
+
+    @Override
+    public int deleteBatch(Integer[] ids) {
+        return merchDao.deleteBatch(ids);
+    }
+}

+ 114 - 0
kmall-admin/src/main/java/com/kmall/admin/service/impl/OrderWXPayRecordServiceImpl.java

@@ -0,0 +1,114 @@
+package com.kmall.admin.service.impl;
+
+import com.kmall.admin.dao.*;
+import com.kmall.admin.entity.*;
+import com.kmall.admin.service.OrderWXPayRecordService;
+import com.kmall.common.utils.Constant;
+import com.kmall.common.utils.RRException;
+import com.kmall.common.utils.wechat.WechatMicropayApiResult;
+import com.kmall.common.utils.wechat.WechatRefundApiResult;
+import com.kmall.common.utils.wechat.WechatUtil;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+
+@Service("orderWXPayRecordService")
+public class OrderWXPayRecordServiceImpl
+        implements OrderWXPayRecordService {
+
+    @Autowired
+    private OrderWXPayRecordDao orderWXPayRecordDao;
+
+
+    @Override
+    public OrderWXPayRecordEntity findByOutTradeNoWX(String outTradeNoWX) {
+        if (StringUtils.isEmpty(outTradeNoWX)) {
+            throw new RRException("订单编号为空");
+        }
+        return orderWXPayRecordDao.findByOutTradeNoWX(outTradeNoWX);
+    }
+
+    @Override
+    public int countByOutTradeNo(String outTradeNo) {
+        if (StringUtils.isEmpty(outTradeNo)) {
+            throw new RRException("订单编号为空");
+        }
+        return orderWXPayRecordDao.countByOutTradeNo(outTradeNo);
+    }
+
+    @Override
+    public List<OrderWXPayRecordEntity> getRecordsByOutTradeNo(String outTradeNo) {
+        if (StringUtils.isEmpty(outTradeNo)) {
+            throw new RRException("订单编号为空");
+        }
+        return orderWXPayRecordDao.getRecordByOutTradeNo(outTradeNo);
+    }
+
+    @Override
+    public OrderWXPayRecordEntity saveRecord(OrderEntity order) {
+        if (order == null) {
+            throw new RRException("订单信息为空");
+        }
+
+        int count = countByOutTradeNo(order.getOrderSn());
+        OrderWXPayRecordEntity orderWXPayRecord = new OrderWXPayRecordEntity();
+        orderWXPayRecord.setFeeType("CNY");
+        orderWXPayRecord.setTotalFee(String.valueOf(order.getActualPrice().multiply(Constant.ONE_HUNDRED).intValue()));
+        orderWXPayRecord.setTradeType("MICROPAY");
+        orderWXPayRecord.setOutTradeNo(order.getOrderSn());
+        orderWXPayRecord.setOutTradeNoWX(order.getOrderSn() + "_" + count);
+        orderWXPayRecord.setCreateTime(new Date());
+        orderWXPayRecord.setModTime(new Date());
+        orderWXPayRecord.setTradeState("NOTPAY");
+        orderWXPayRecordDao.save(orderWXPayRecord);
+        return orderWXPayRecord;
+    }
+
+    @Override
+    public int updateRecord(Integer id, WechatMicropayApiResult wechatMicropayApiResult) {
+        OrderWXPayRecordEntity orderWXPayRecord = new OrderWXPayRecordEntity();
+        orderWXPayRecord.setId(id);
+        orderWXPayRecord.setReturnCode(wechatMicropayApiResult.getReturn_code());
+        orderWXPayRecord.setReturnMsg(wechatMicropayApiResult.getReturn_msg());
+        orderWXPayRecord.setResultCode(wechatMicropayApiResult.getResult_code());
+        orderWXPayRecord.setErrCode(wechatMicropayApiResult.getErr_code());
+        orderWXPayRecord.setErrCodeDes(wechatMicropayApiResult.getErr_code_des());
+        orderWXPayRecord.setOpenid(wechatMicropayApiResult.getOpenid());
+        orderWXPayRecord.setIsSubscribe(wechatMicropayApiResult.getIs_subscribe());
+        orderWXPayRecord.setTradeType(wechatMicropayApiResult.getTrade_type());
+        orderWXPayRecord.setFeeType(wechatMicropayApiResult.getFee_type());
+        orderWXPayRecord.setTotalFee(wechatMicropayApiResult.getTotal_fee());
+        orderWXPayRecord.setTransactionId(wechatMicropayApiResult.getTransaction_id());
+        orderWXPayRecord.setAttach(wechatMicropayApiResult.getAttach());
+        orderWXPayRecord.setTimeEnd(wechatMicropayApiResult.getTime_end());
+        orderWXPayRecord.setTradeState(wechatMicropayApiResult.getTrade_state());
+        orderWXPayRecord.setModTime(new Date());
+        orderWXPayRecordDao.update(orderWXPayRecord);
+        return 0;
+    }
+
+    @Override
+    public int updateWXPayRecordTradeState(Integer id, WechatRefundApiResult wechatRefundApiResult) {
+        OrderWXPayRecordEntity orderWXPayRecord = new OrderWXPayRecordEntity();
+        orderWXPayRecord.setId(id);
+        orderWXPayRecord.setTradeState(wechatRefundApiResult.getTrade_state());
+        if(WechatUtil.WXTradeState.SUCCESS.getCode().equals(orderWXPayRecord.getTradeState())){
+            orderWXPayRecord.setResultCode(orderWXPayRecord.getTradeState());
+            orderWXPayRecord.setErrCode("");
+            orderWXPayRecord.setErrCodeDes("");
+            orderWXPayRecord.setOpenid(wechatRefundApiResult.getOpenid());
+            orderWXPayRecord.setIsSubscribe(wechatRefundApiResult.getIs_subscribe());
+            orderWXPayRecord.setTradeType(wechatRefundApiResult.getTrade_type());
+            orderWXPayRecord.setFeeType(wechatRefundApiResult.getFee_type());
+            orderWXPayRecord.setTotalFee(wechatRefundApiResult.getTotal_fee());
+            orderWXPayRecord.setTransactionId(wechatRefundApiResult.getTransaction_id());
+            orderWXPayRecord.setAttach(wechatRefundApiResult.getAttach());
+        }
+        orderWXPayRecord.setModTime(new Date());
+        orderWXPayRecordDao.update(orderWXPayRecord);
+        return 0;
+    }
+}

+ 4 - 0
kmall-admin/src/main/resources/conf/wx-mp.properties

@@ -35,6 +35,10 @@ wx.dev.refundNotifyUrl=http://qhdswl.f3322.net:9001/platform-framework/api/pay/r
 wx.dev.refundqueryUrl=https://api.mch.weixin.qq.com/pay/refundquery
 #微信查询订单状态
 wx.dev.orderquery=https://api.mch.weixin.qq.com/pay/orderquery
+#提交付款码支付
+wx.dev.micropay=https://api.mch.weixin.qq.com/pay/micropay
+#撤销订单
+wx.dev.reverse=https://api.mch.weixin.qq.com/secapi/pay/reverse
 #服务器Ip
 wx.dev.spbillCreateIp=127.0.0.1
 

+ 149 - 0
kmall-admin/src/main/resources/mybatis/mapper/MerchDao.xml

@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="com.kmall.admin.dao.MerchDao">
+
+    <resultMap type="com.kmall.admin.entity.MerchEntity" id="merchMap">
+        <result property="id" column="id"/>
+        <result property="merchSn" column="merch_sn"/>
+        <result property="merchName" column="merch_name"/>
+        <result property="merchShortName" column="merch_short_name"/>
+        <result property="merchImg" column="merch_img"/>
+        <result property="sortOrder" column="sort_order"/>
+		<result property="isShow" column="is_show"/>
+        <result property="remark" column="remark"/>
+        <result property="createrSn" column="creater_sn"/>
+        <result property="createTime" column="create_time"/>
+        <result property="moderSn" column="moder_sn"/>
+        <result property="modTime" column="mod_time"/>
+        <result property="tstm" column="tstm"/>
+    </resultMap>
+
+	<select id="queryObject" resultType="com.kmall.admin.entity.MerchEntity">
+		select
+			`id`,
+			`merch_sn`,
+			`merch_name`,
+			`merch_short_name`,
+			`merch_img`,
+			`sort_order`,
+			`is_show`,
+			`remark`,
+			`creater_sn`,
+			`create_time`,
+			`moder_sn`,
+			`mod_time`,
+			`tstm`,
+			`is_show` as `show`
+		from mall_merch
+		where id = #{id}
+	</select>
+
+	<select id="queryList" resultType="com.kmall.admin.entity.MerchEntity">
+		select
+    		`id`,
+    		`merch_sn`,
+    		`merch_name`,
+    		`merch_short_name`,
+    		`merch_img`,
+    		`sort_order`,
+			`is_show`,
+    		`remark`,
+    		`creater_sn`,
+    		`create_time`,
+    		`moder_sn`,
+    		`mod_time`,
+    		`tstm`,
+			`is_show` as `show`
+		from mall_merch
+		WHERE 1=1
+		<if test="merchName != null and merchName.trim() != ''">
+			AND merch_name LIKE concat('%',#{merchName},'%')
+		</if>
+		<if test="merchSn != null and merchSn.trim() != ''">
+			AND merch_sn LIKE concat('%',#{merchSn},'%')
+		</if>
+        <choose>
+            <when test="sidx != null and sidx.trim() != ''">
+                order by ${sidx} ${order}
+            </when>
+			<otherwise>
+                order by id desc
+			</otherwise>
+        </choose>
+		<if test="offset != null and limit != null">
+			limit #{offset}, #{limit}
+		</if>
+	</select>
+	
+ 	<select id="queryTotal" resultType="int">
+		select count(*) from mall_merch
+		WHERE 1=1
+		<if test="merchName != null and merchName.trim() != ''">
+			AND merch_name LIKE concat('%',#{merchName},'%')
+		</if>
+		<if test="merchSn != null and merchSn.trim() != ''">
+			AND merch_sn LIKE concat('%',#{merchSn},'%')
+		</if>
+	</select>
+	 
+	<insert id="save" parameterType="com.kmall.admin.entity.MerchEntity" useGeneratedKeys="true" keyProperty="id">
+		insert into mall_merch(
+			`merch_sn`,
+			`merch_name`,
+			`merch_short_name`,
+			`merch_img`,
+			`sort_order`,
+			`is_show`,
+			`remark`,
+			`creater_sn`,
+			`create_time`,
+			`moder_sn`,
+			`mod_time`,
+			`tstm`)
+		values(
+			#{merchSn},
+			#{merchName},
+			#{merchShortName},
+			#{merchImg},
+			#{sortOrder},
+			#{isShow},
+			#{remark},
+			#{createrSn},
+			#{createTime},
+			#{moderSn},
+			#{modTime},
+			#{tstm})
+	</insert>
+	 
+	<update id="update" parameterType="com.kmall.admin.entity.MerchEntity">
+		update mall_merch 
+		<set>
+			<if test="merchSn != null">`merch_sn` = #{merchSn}, </if>
+			<if test="merchName != null">`merch_name` = #{merchName}, </if>
+			<if test="merchShortName != null">`merch_short_name` = #{merchShortName}, </if>
+			<if test="merchImg != null">`merch_img` = #{merchImg}, </if>
+			<if test="sortOrder != null">`sort_order` = #{sortOrder}, </if>
+			<if test="isShow != null">`is_show` = #{isShow}, </if>
+			<if test="remark != null">`remark` = #{remark}, </if>
+			<if test="createrSn != null">`creater_sn` = #{createrSn}, </if>
+			<if test="createTime != null">`create_time` = #{createTime}, </if>
+			<if test="moderSn != null">`moder_sn` = #{moderSn}, </if>
+			<if test="modTime != null">`mod_time` = #{modTime}, </if>
+			<if test="tstm != null">`tstm` = #{tstm}</if>
+		</set>
+		where id = #{id}
+	</update>
+	
+	<delete id="delete">
+		delete from mall_merch where id = #{value}
+	</delete>
+	
+	<delete id="deleteBatch">
+		delete from mall_merch where id in 
+		<foreach item="id" collection="array" open="(" separator="," close=")">
+			#{id}
+		</foreach>
+	</delete>
+
+</mapper>

+ 118 - 0
kmall-admin/src/main/resources/mybatis/mapper/OrderWXPayRecordDao.xml

@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="com.kmall.admin.dao.OrderWXPayRecordDao">
+
+    <resultMap type="com.kmall.admin.entity.OrderWXPayRecordEntity" id="OrderWXPayRecordMap">
+        <result property="id" column="id"/>
+        <result property="returnCode" column="return_code"/>
+        <result property="returnMsg" column="return_msg"/>
+        <result property="resultCode" column="result_code"/>
+        <result property="errCode" column="err_code"/>
+        <result property="errCodeDes" column="err_code_des"/>
+        <result property="openid" column="openid"/>
+        <result property="isSubscribe" column="is_subscribe"/>
+        <result property="tradeType" column="trade_type"/>
+		<result property="feeType" column="fee_type"/>
+		<result property="totalFee" column="total_fee"/>
+		<result property="transactionId" column="transaction_id"/>
+		<result property="outTradeNo" column="out_trade_no"/>
+		<result property="outTradeNoWX" column="out_trade_no_wx"/>
+		<result property="attach" column="attach"/>
+		<result property="timeEnd" column="time_end"/>
+		<result property="tradeState" column="trade_state"/>
+		<result property="createrSn" column="creater_sn"/>
+		<result property="createTime" column="create_time"/>
+		<result property="moderSn" column="moder_sn"/>
+		<result property="modTime" column="mod_time"/>
+		<result property="tstm" column="tstm"/>
+    </resultMap>
+
+	<select id="queryObject" resultMap="OrderWXPayRecordMap">
+		select *
+        from mall_order_wxpay_record
+        where id = #{id}
+	</select>
+
+	<select id="getRecordByOutTradeNo" resultMap="OrderWXPayRecordMap">
+        select *
+        from mall_order_wxpay_record
+        where out_trade_no = #{outTradeNo}
+    </select>
+
+ 	<select id="countByOutTradeNo" resultType="int">
+		select count(id) from mall_order_wxpay_record where out_trade_no = #{outTradeNo}
+	</select>
+	 
+	<insert id="save" parameterType="com.kmall.admin.entity.OrderWXPayRecordEntity" useGeneratedKeys="true" keyProperty="id">
+		insert into mall_order_wxpay_record(
+			`return_code`,
+			`return_msg`,
+			`result_code`,
+			`err_code`,
+			`err_code_des`,
+			`openid`,
+			`is_subscribe`,
+			`trade_type`,
+			`fee_type`,
+			`total_fee`,
+			`transaction_id`,
+			`out_trade_no`,
+			`out_trade_no_wx`,
+			`attach`,
+			`time_end`,
+			`trade_state`,
+			`creater_sn`,
+			`create_time`,
+			`moder_sn`,
+			`mod_time`)
+		values(
+			#{returnCode},
+			#{returnMsg},
+			#{resultCode},
+			#{errCode},
+			#{errCodeDes},
+			#{openid},
+			#{isSubscribe},
+			#{tradeType},
+			#{feeType},
+			#{totalFee},
+			#{transactionId},
+			#{outTradeNo},
+			#{outTradeNoWX},
+			#{attach},
+			#{timeEnd},
+			#{tradeState},
+			#{createrSn},
+			#{createTime},
+			#{moderSn},
+			#{modTime})
+	</insert>
+	 
+	<update id="update" parameterType="com.kmall.admin.entity.OrderWXPayRecordEntity">
+		update mall_order_wxpay_record
+		<set>
+			<if test="returnCode != null">`return_code` = #{returnCode}, </if>
+			<if test="returnMsg != null">`return_msg` = #{returnMsg}, </if>
+			<if test="resultCode != null">`result_code` = #{resultCode}, </if>
+			<if test="errCode != null">`err_code` = #{errCode}, </if>
+			<if test="errCodeDes != null">`err_code_des` = #{errCodeDes}, </if>
+			<if test="openid != null">`openid` = #{openid}, </if>
+			<if test="isSubscribe != null">`is_subscribe` = #{isSubscribe}, </if>
+			<if test="tradeType != null">`trade_type` = #{tradeType}, </if>
+			<if test="feeType != null">`fee_type` = #{feeType}, </if>
+			<if test="totalFee != null">`total_fee` = #{totalFee}, </if>
+			<if test="transactionId != null">`transaction_id` = #{transactionId}, </if>
+			<if test="outTradeNo != null">`out_trade_no` = #{outTradeNo}, </if>
+			<if test="outTradeNoWX != null">`out_trade_no_wx` = #{outTradeNoWX}, </if>
+			<if test="attach != null">`attach` = #{attach}, </if>
+			<if test="timeEnd != null">`time_end` = #{timeEnd}, </if>
+			<if test="tradeState != null">`trade_state` = #{tradeState}, </if>
+			<if test="createrSn != null">`creater_sn` = #{createrSn}, </if>
+			<if test="createTime != null">`create_time` = #{createTime}, </if>
+			<if test="moderSn != null">`moder_sn` = #{moderSn}, </if>
+			<if test="modTime != null">`mod_time` = #{modTime}</if>
+		</set>
+		where id = #{id}
+	</update>
+</mapper>

+ 76 - 0
kmall-admin/src/main/webapp/WEB-INF/page/shop/merch.html

@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title></title>
+    #parse("sys/header.html")
+</head>
+<body>
+<div id="rrapp" v-cloak>
+	<div v-show="showList">
+        <Row :gutter="16">
+            <div class="search-group">
+                <i-col span="3">
+                    <i-input v-model="q.merchName" @on-enter="query" placeholder="商户名称"/>
+                </i-col>
+                <i-col span="3">
+                    <i-input v-model="q.merchSn" @on-enter="query" placeholder="商户编号"/>
+                </i-col>
+                <i-button @click="query">查询</i-button>
+                <i-button @click="reloadSearch">重置</i-button>
+            </div>
+            <div class="buttons-group">
+                #if($shiro.hasPermission("merch:save"))
+                <i-button type="info" @click="add"><i class="fa fa-plus"></i>&nbsp;新增</i-button>
+                #end
+                #if($shiro.hasPermission("merch:update"))
+                <i-button type="warning" @click="update"><i class="fa fa-pencil-square-o"></i>&nbsp;修改</i-button>
+                #end
+                #if($shiro.hasPermission("merch:delete"))
+                <i-button type="error" @click="del"><i class="fa fa-trash-o"></i>&nbsp;删除</i-button>
+                #end
+            </div>
+        </Row>
+	    <table id="jqGrid"></table>
+	    <div id="jqGridPager"></div>
+    </div>
+
+    <Card v-show="!showList">
+        <p slot="title">{{title}}</p>
+		<i-form ref="formValidate" :model="merch" :rules="ruleValidate" :label-width="80">
+            <Form-item label="商户编号" prop="merchSn">
+                <i-input v-model="merch.merchSn" placeholder="商户编号"/>
+            </Form-item>
+            <Form-item label="商户名称" prop="merchName">
+                <i-input v-model="merch.merchName" placeholder="商户名称"/>
+            </Form-item>
+            <Form-item label="商户简称" prop="merchShortName">
+                <i-input v-model="merch.merchShortName" placeholder="商户简称"/>
+            </Form-item>
+            <Form-item label="排序" prop="sortOrder">
+                <i-input v-model="merch.sortOrder" placeholder="排序"/>
+            </Form-item>
+            <Form-item label="显示" prop="isShow">
+                <Radio-group v-model="merch.isShow">
+                    <Radio label="1">
+                        <span>是</span>
+                    </Radio>
+                    <Radio label="0">
+                        <span>否</span>
+                    </Radio>
+                </Radio-group>
+            </Form-item>
+            <Form-item label="备注" prop="remark">
+                <i-input v-model="merch.remark" placeholder="备注"/>
+            </Form-item>
+            <Form-item>
+                <i-button type="primary" @click="handleSubmit('formValidate')">提交</i-button>
+                <i-button type="warning" @click="reload" style="margin-left: 8px"/>返回</i-button>
+                <i-button type="ghost" @click="handleReset('formValidate')" style="margin-left: 8px">重置</i-button>
+            </Form-item>
+        </i-form>
+	</Card>
+</div>
+
+<script src="${rc.contextPath}/js/shop/merch.js?_${date.systemTime}"></script>
+</body>
+</html>

+ 27 - 1
kmall-admin/src/main/webapp/WEB-INF/page/shop/offilineOrderList.html

@@ -34,7 +34,10 @@
                 <i-button @click="reloadSearch">重置</i-button>
             </div>
             <div class="buttons-group">
-                <i-button type="error" @click="confirm">确认付款</i-button>
+                <i-button type="error" @click="showInputAuthCode">微信付款</i-button>
+            </div>
+            <div class="buttons-group">
+                <i-button type="error" @click="confirm">现金付款</i-button>
             </div>
         </Row>
         <table id="jqGrid"></table>
@@ -205,6 +208,29 @@
                 </table>
                 <i-button type="warning" @click="reload" style="margin-left: 8px"/>返回</i-button>
             </Tab-Pane>
+            <Tab-Pane label="支付记录" name="name3">
+                <table class="table">
+                    <tr>
+                        <td style="text-align: left; width: 240px; font-weight: bold;">支付编号</td>
+                        <td style="text-align: center; width: 240px; font-weight: bold;">支付金额(分)</td>
+                        <td style="text-align: center; width: 240px; font-weight: bold;">交易状态</td>
+                        <td style="text-align: center; width: 600px; font-weight: bold;">描述</td>
+                    </tr>
+                    <tr v-for="(item,index) in payRecordList">
+                        <td align="center">{{item.outTradeNoWX}}</td>
+                        <td align="center">{{item.totalFee}}</td>
+                        <td align="center" v-show="item.tradeState == 'SUCCESS'">支付成功</td>
+                        <td align="center" v-show="item.tradeState == 'REFUND'">转入退款</td>
+                        <td align="center" v-show="item.tradeState == 'NOTPAY'">未支付</td>
+                        <td align="center" v-show="item.tradeState == 'CLOSED'">已关闭</td>
+                        <td align="center" v-show="item.tradeState == 'REVOKED'">已撤销</td>
+                        <td align="center" v-show="item.tradeState == 'USERPAYING'">用户支付中</td>
+                        <td align="center" v-show="item.tradeState == 'PAYERROR'">支付失败</td>
+                        <td align="center">{{item.errCodeDes}}</td>
+                    </tr>
+                </table>
+                <i-button type="warning" @click="reload" style="margin-left: 8px"/>返回</i-button>
+            </Tab-Pane>
         </Tabs>
     </Card>
 

+ 161 - 0
kmall-admin/src/main/webapp/js/shop/merch.js

@@ -0,0 +1,161 @@
+$(function () {
+    $("#jqGrid").jqGrid({
+        url: '../merch/list',
+        datatype: "json",
+        colModel: [
+			{label: 'id', name: 'id', index: 'id', key: true, hidden: true},
+			{label: '商户编号', name: 'merchSn', index: 'merch_sn', width: 80},
+			{label: '商户名称', name: 'merchName', index: 'merch_name', width: 80},
+			{label: '商户简称', name: 'merchShortName', index: 'merch_short_name', width: 80},
+			{label: '排序', name: 'sortOrder', index: 'sort_order', width: 80},
+            {
+                label: '显示',
+                name: 'isShow',
+                align: 'center',
+                index: 'is_show',
+                width: '50px',
+                formatter: function (value) {
+                    return transIsNot(value);
+                }
+            },
+			{label: '备注', name: 'remark', index: 'remark', width: 80}],
+		viewrecords: true,
+        height: 385,
+        rowNum: 10,
+        rowList: [10, 30, 50],
+        rownumbers: true,
+        rownumWidth: 25,
+        autowidth: true,
+        multiselect: true,
+        pager: "#jqGridPager",
+        jsonReader: {
+            root: "page.list",
+            page: "page.currPage",
+            total: "page.totalPage",
+            records: "page.totalCount"
+        },
+        prmNames: {
+            page: "page",
+            rows: "limit",
+            order: "order"
+        },
+        gridComplete: function () {
+            $("#jqGrid").closest(".ui-jqgrid-bdiv").css({"overflow-x": "hidden"});
+        }
+    });
+});
+
+let vm = new Vue({
+	el: '#rrapp',
+	data: {
+        showList: true,
+        title: null,
+		merch: {merchSn:'',merchName:'',merchShortName:'',sortOrder:'',isShow:''},
+		ruleValidate: {
+            merchSn: [
+				{required: true, message: '商户编号不能为空', trigger: 'blur'}
+			],
+            merchName: [
+                {required: true, message: '商户名称不能为空', trigger: 'blur'}
+            ],
+            merchShortName: [
+                {required: true, message: '商户简称不能为空', trigger: 'blur'}
+            ]
+		},
+		q: {
+            merchName: '',
+            merchSn: ''
+		}
+	},
+	methods: {
+		query: function () {
+			vm.reload();
+		},
+		add: function () {
+			vm.showList = false;
+			vm.title = "新增";
+			vm.merch = {};
+		},
+		update: function (event) {
+            let id = getSelectedRow();
+			if (id == null) {
+				return;
+			}
+			vm.showList = false;
+            vm.title = "修改";
+
+            vm.getInfo(id)
+		},
+		saveOrUpdate: function (event) {
+            let url = vm.merch.id == null ? "../merch/save" : "../merch/update";
+			$.ajax({
+				type: "POST",
+			    url: url,
+			    contentType: "application/json",
+			    data: JSON.stringify(vm.merch),
+                success: function (r) {
+                    if (r.code === 0) {
+                        alert('操作成功', function (index) {
+                            vm.reload();
+                        });
+                    } else {
+                        alert(r.msg);
+                    }
+                }
+			});
+		},
+		del: function (event) {
+            let ids = getSelectedRows();
+			if (ids == null){
+				return;
+			}
+
+			confirm('确定要删除选中的记录?', function () {
+				$.ajax({
+					type: "POST",
+				    url: "../merch/delete",
+				    contentType: "application/json",
+				    data: JSON.stringify(ids),
+				    success: function (r) {
+						if (r.code == 0) {
+							alert('操作成功', function (index) {
+								$("#jqGrid").trigger("reloadGrid");
+							});
+						} else {
+							alert(r.msg);
+						}
+					}
+				});
+			});
+		},
+		getInfo: function(id){
+			$.get("../merch/info/"+id, function (r) {
+                vm.merch = r.merch;
+            });
+		},
+        reloadSearch: function() {
+            vm.q = {
+                merchName: '',
+                merchSn:''
+            }
+            vm.reload();
+		},
+		reload: function (event) {
+			vm.showList = true;
+            let page = $("#jqGrid").jqGrid('getGridParam', 'page');
+			$("#jqGrid").jqGrid('setGridParam', {
+                postData: {'merchName': vm.q.merchName,'merchSn': vm.q.merchSn},
+                page: page
+            }).trigger("reloadGrid");
+            vm.handleReset('formValidate');
+		},
+        handleSubmit: function (name) {
+            handleSubmitValidate(this, name, function () {
+                vm.saveOrUpdate()
+            });
+        },
+        handleReset: function (name) {
+            handleResetForm(this, name);
+        }
+	}
+});

+ 93 - 1
kmall-admin/src/main/webapp/js/shop/offilineOrderList.js

@@ -179,7 +179,8 @@ let vm = new Vue({
         },
         macros: [],
         orderProcessRecordEntity: {},
-        orderGoodsList: []
+        orderGoodsList: [],
+        payRecordList:[]
     },
     methods: {
         query: function () {
@@ -239,6 +240,7 @@ let vm = new Vue({
             $.get("../order/offlineInfos/" + rowId, function (r) {
                 vm.order = r.order;
                 vm.orderGoodsList = r.order.orderGoodsEntityList;
+                vm.payRecordList = r.order.payRecordList;
             });
             vm.getMacro();
         },
@@ -287,6 +289,77 @@ let vm = new Vue({
                 });
             });
         },
+        showInputAuthCode: function (event) {
+            let id = getSelectedRow();
+            if (id == null) {
+                return;
+            }
+
+            var layer_index = layer.prompt({title: '请输入微信付款码',
+                formType: 3,   //隐藏用户输入内容
+                // 这个是确定按钮的事件
+                "success":function(layero,index){
+                    // 键盘事件,判断回车
+                    $("input.layui-layer-input").on('keydown',function(e){
+                        if (e.which == 13) {
+                            var authCode = $(this).val();
+                            if (authCode == null || authCode == "") {
+                                iview.Message.error("请输入微信付款码");
+                                return;
+                            }
+
+                            layer.close(layer_index);
+                            var msg_index = layer.msg('支付中', {
+                                icon: 16
+                                ,shade: 0.01
+                            });
+                            wxPay(authCode,id,msg_index);
+                        }
+                    });
+                },
+                // 点击确定按钮事件
+                yes : function(index,layero){
+                    // 取输入框数据
+                    var authCode =$(document.getElementsByClassName('layui-layer-input')[0]).val();
+                    if (authCode == null || authCode == "") {
+                        iview.Message.error("请输入微信付款码");
+                        return;
+                    }
+
+                    layer.close(layer_index);
+                    var msg_index = layer.msg('支付中', {
+                        icon: 16,
+                        shade: 0.01
+                    });
+                    wxPay(authCode,id,msg_index);
+                }
+            });
+
+            // layer.prompt({title: '请输入微信付款码', formType: 3}, function(pass, index){
+            //     var authCode= pass;
+            //     if (authCode == null || authCode == "") {
+            //         iview.Message.error("请输入微信付款码");
+            //         return;
+            //     }
+            //
+            //     $.ajax({
+            //         type: "POST",
+            //         url: '../order/wxMicropayPay',
+            //         data: {auth_code: authCode, id: id},
+            //         success: function (r) {
+            //             if (r.code === 0) {
+            //                 alert('支付成功', function (index) {
+            //                     vm.reload();
+            //                 });
+            //             } else {
+            //                 alert(r.msg);
+            //             }
+            //         }
+            //     });
+            //
+            //     layer.close(index);
+            // });
+        },
         shippingBind: function (event) {
             let orderId = vm.order.id;
             $.ajax({
@@ -458,6 +531,25 @@ let vm = new Vue({
         content += "</div>";
         return content;
     }
+
+    function wxPay(authCode,id,msg_index){
+        $.ajax({
+            type: "POST",
+            url: '../order/wxMicropayPay',
+            data: {auth_code: authCode, id: id},
+            success: function (r) {
+                layer.close(msg_index);
+                if (r.code === 0) {
+                    alert('支付成功', function (index) {
+                        vm.reload();
+                    });
+                } else {
+                    alert(r.msg);
+                }
+            }
+        });
+    }
+
     var printAreaCount = 0;
     function printArea(content) {
         var idPrefix = "printArea_";

+ 18 - 0
kmall-api/src/main/java/com/kmall/api/service/pay/wxpay/WxPayProperties.java

@@ -28,9 +28,27 @@ public class WxPayProperties implements Serializable {
 
     private String refundqueryUrl;
     private String orderquery;
+    private String micropayUrl;
+    private String reverseUrl;
     private String spbillCreateIp;
     private String refundNotifyUrl;
 
+    public String getMicropayUrl() {
+        return micropayUrl;
+    }
+
+    public void setMicropayUrl(String micropayUrl) {
+        this.micropayUrl = micropayUrl;
+    }
+
+    public String getReverseUrl() {
+        return reverseUrl;
+    }
+
+    public void setReverseUrl(String reverseUrl) {
+        this.reverseUrl = reverseUrl;
+    }
+
     public String getRefundNotifyUrl() {
         return refundNotifyUrl;
     }

+ 18 - 0
kmall-common/src/main/java/com/kmall/common/service/pay/wxpay/CommonWxPayProperties.java

@@ -28,9 +28,27 @@ public class CommonWxPayProperties implements Serializable {
 
     private String refundqueryUrl;
     private String orderquery;
+    private String micropayUrl;
+    private String reverseUrl;
     private String spbillCreateIp;
     private String refundNotifyUrl;
 
+    public String getMicropayUrl() {
+        return micropayUrl;
+    }
+
+    public void setMicropayUrl(String micropayUrl) {
+        this.micropayUrl = micropayUrl;
+    }
+
+    public String getReverseUrl() {
+        return reverseUrl;
+    }
+
+    public void setReverseUrl(String reverseUrl) {
+        this.reverseUrl = reverseUrl;
+    }
+
     public String getRefundNotifyUrl() {
         return refundNotifyUrl;
     }

+ 258 - 0
kmall-common/src/main/java/com/kmall/common/utils/wechat/WechatMicropayApiResult.java

@@ -0,0 +1,258 @@
+package com.kmall.common.utils.wechat;
+
+public class WechatMicropayApiResult {
+	private String return_code;//返回状态码
+	private String return_msg;//返回信息
+
+	private String appid;//公众账号ID
+	private String mch_id;//商户号
+	private String device_info;//设备号
+	private String nonce_str;//随机字符串
+	private String sign;//签名
+	private String result_code;//业务结果
+	private String err_code;//错误代码
+	private String err_code_des;//错误代码描述
+
+
+
+	private String openid;//用户标识
+	private String is_subscribe;//是否关注公众账号
+	private String trade_type;//交易类型(MICROPAY 付款码支付)
+	private String bank_type;//付款银行
+	private String fee_type;//货币类型
+	private String total_fee;//订单金额
+	private String settlement_total_fee;//应结订单金额
+	private String coupon_fee;//代金券金额
+	private String cash_fee_type;//现金支付货币类型
+	private String cash_fee;//现金支付金额
+	private String transaction_id;//微信支付订单号
+	private String out_trade_no;//商户订单号
+	private String attach;//商家数据包
+	private String time_end;//支付完成时间
+
+	/**
+	 * SUCCESS—支付成功
+	 REFUND—转入退款
+	 NOTPAY—未支付
+	 CLOSED—已关闭
+	 REVOKED—已撤销(刷卡支付)
+	 USERPAYING--用户支付中
+	 PAYERROR--支付失败(其他原因,如银行返回失败)
+	 */
+	private String trade_state;//交易状态
+
+
+	public String getReturn_code() {
+		return return_code;
+	}
+
+	public void setReturn_code(String return_code) {
+		this.return_code = return_code;
+	}
+
+	public String getReturn_msg() {
+		return return_msg;
+	}
+
+	public void setReturn_msg(String return_msg) {
+		this.return_msg = return_msg;
+	}
+
+	public String getAppid() {
+		return appid;
+	}
+
+	public void setAppid(String appid) {
+		this.appid = appid;
+	}
+
+	public String getMch_id() {
+		return mch_id;
+	}
+
+	public void setMch_id(String mch_id) {
+		this.mch_id = mch_id;
+	}
+
+	public String getDevice_info() {
+		return device_info;
+	}
+
+	public void setDevice_info(String device_info) {
+		this.device_info = device_info;
+	}
+
+	public String getNonce_str() {
+		return nonce_str;
+	}
+
+	public void setNonce_str(String nonce_str) {
+		this.nonce_str = nonce_str;
+	}
+
+	public String getSign() {
+		return sign;
+	}
+
+	public void setSign(String sign) {
+		this.sign = sign;
+	}
+
+	public String getResult_code() {
+		return result_code;
+	}
+
+	public void setResult_code(String result_code) {
+		this.result_code = result_code;
+	}
+
+	public String getErr_code() {
+		return err_code;
+	}
+
+	public void setErr_code(String err_code) {
+		this.err_code = err_code;
+	}
+
+	public String getErr_code_des() {
+		return err_code_des;
+	}
+
+	public void setErr_code_des(String err_code_des) {
+		this.err_code_des = err_code_des;
+	}
+
+	public String getOpenid() {
+		return openid;
+	}
+
+	public void setOpenid(String openid) {
+		this.openid = openid;
+	}
+
+	public String getIs_subscribe() {
+		return is_subscribe;
+	}
+
+	public void setIs_subscribe(String is_subscribe) {
+		this.is_subscribe = is_subscribe;
+	}
+
+	public String getTrade_type() {
+		return trade_type;
+	}
+
+	public void setTrade_type(String trade_type) {
+		this.trade_type = trade_type;
+	}
+
+	public String getBank_type() {
+		return bank_type;
+	}
+
+	public void setBank_type(String bank_type) {
+		this.bank_type = bank_type;
+	}
+
+	public String getFee_type() {
+		return fee_type;
+	}
+
+	public void setFee_type(String fee_type) {
+		this.fee_type = fee_type;
+	}
+
+	public String getTotal_fee() {
+		return total_fee;
+	}
+
+	public void setTotal_fee(String total_fee) {
+		this.total_fee = total_fee;
+	}
+
+	public String getSettlement_total_fee() {
+		return settlement_total_fee;
+	}
+
+	public void setSettlement_total_fee(String settlement_total_fee) {
+		this.settlement_total_fee = settlement_total_fee;
+	}
+
+	public String getCoupon_fee() {
+		return coupon_fee;
+	}
+
+	public void setCoupon_fee(String coupon_fee) {
+		this.coupon_fee = coupon_fee;
+	}
+
+	public String getCash_fee_type() {
+		return cash_fee_type;
+	}
+
+	public void setCash_fee_type(String cash_fee_type) {
+		this.cash_fee_type = cash_fee_type;
+	}
+
+	public String getCash_fee() {
+		return cash_fee;
+	}
+
+	public void setCash_fee(String cash_fee) {
+		this.cash_fee = cash_fee;
+	}
+
+	public String getTransaction_id() {
+		return transaction_id;
+	}
+
+	public void setTransaction_id(String transaction_id) {
+		this.transaction_id = transaction_id;
+	}
+
+	public String getOut_trade_no() {
+		return out_trade_no;
+	}
+
+	public void setOut_trade_no(String out_trade_no) {
+		this.out_trade_no = out_trade_no;
+	}
+
+	public String getAttach() {
+		return attach;
+	}
+
+	public void setAttach(String attach) {
+		this.attach = attach;
+	}
+
+	public String getTime_end() {
+		return time_end;
+	}
+
+	public void setTime_end(String time_end) {
+		this.time_end = time_end;
+	}
+
+	public String getTrade_state() {
+		return trade_state;
+	}
+
+	public void setTrade_state(String trade_state) {
+		this.trade_state = trade_state;
+	}
+
+	@Override
+	public String toString() {
+		return "WechatMicropayApiResult{" + "return_code='" + return_code + '\'' + ", return_msg='" + return_msg +
+			   '\'' + ", appid='" + appid + '\'' + ", mch_id='" + mch_id + '\'' + ", device_info='" + device_info +
+			   '\'' + ", nonce_str='" + nonce_str + '\'' + ", sign='" + sign + '\'' + ", result_code='" + result_code +
+			   '\'' + ", err_code='" + err_code + '\'' + ", err_code_des='" + err_code_des + '\'' + ", openid='" +
+			   openid + '\'' + ", is_subscribe='" + is_subscribe + '\'' + ", trade_type='" + trade_type + '\'' +
+			   ", bank_type='" + bank_type + '\'' + ", fee_type='" + fee_type + '\'' + ", total_fee='" + total_fee +
+			   '\'' + ", settlement_total_fee='" + settlement_total_fee + '\'' + ", coupon_fee='" + coupon_fee + '\'' +
+			   ", cash_fee_type='" + cash_fee_type + '\'' + ", cash_fee='" + cash_fee + '\'' + ", transaction_id='" +
+			   transaction_id + '\'' + ", out_trade_no='" + out_trade_no + '\'' + ", attach='" + attach + '\'' +
+			   ", time_end='" + time_end + '\'' + ", trade_state='" + trade_state + '\'' + '}';
+	}
+}

+ 38 - 0
kmall-common/src/main/java/com/kmall/common/utils/wechat/WechatRefundApiResult.java

@@ -30,6 +30,12 @@ public class WechatRefundApiResult {
 	private String refund_account;//退款资金来源
 	private String refund_recv_accout;//退款入账账户
 	private String success_time;//退款成功时间
+
+	private String openid;//用户标识
+	private String is_subscribe;//是否关注公众账号
+	private String trade_type;//交易类型(MICROPAY 付款码支付)
+
+	private String attach;//商家数据包
 	/**
 	 * SUCCESS—支付成功
 	 REFUND—转入退款
@@ -41,6 +47,38 @@ public class WechatRefundApiResult {
 	 */
 	private String trade_state;//交易状态
 
+	public String getOpenid() {
+		return openid;
+	}
+
+	public void setOpenid(String openid) {
+		this.openid = openid;
+	}
+
+	public String getIs_subscribe() {
+		return is_subscribe;
+	}
+
+	public void setIs_subscribe(String is_subscribe) {
+		this.is_subscribe = is_subscribe;
+	}
+
+	public String getTrade_type() {
+		return trade_type;
+	}
+
+	public void setTrade_type(String trade_type) {
+		this.trade_type = trade_type;
+	}
+
+	public String getAttach() {
+		return attach;
+	}
+
+	public void setAttach(String attach) {
+		this.attach = attach;
+	}
+
 	public String getTrade_state() {
 		return trade_state;
 	}

+ 97 - 0
kmall-common/src/main/java/com/kmall/common/utils/wechat/WechatReverseApiResult.java

@@ -0,0 +1,97 @@
+package com.kmall.common.utils.wechat;
+
+public class WechatReverseApiResult {
+
+	private String return_code;//返回状态码
+	private String return_msg;//返回信息
+
+	private String appid;//公众账号ID
+	private String mch_id;//商户号
+	private String nonce_str;//随机字符串
+	private String sign;//签名
+	private String result_code;//业务结果
+	private String err_code;//错误代码
+	private String err_code_des;//错误代码描述
+	private String recall;//是否需要继续调用撤销,Y-需要,N-不需要
+
+	public String getReturn_code() {
+		return return_code;
+	}
+
+	public void setReturn_code(String return_code) {
+		this.return_code = return_code;
+	}
+
+	public String getReturn_msg() {
+		return return_msg;
+	}
+
+	public void setReturn_msg(String return_msg) {
+		this.return_msg = return_msg;
+	}
+
+	public String getAppid() {
+		return appid;
+	}
+
+	public void setAppid(String appid) {
+		this.appid = appid;
+	}
+
+	public String getMch_id() {
+		return mch_id;
+	}
+
+	public void setMch_id(String mch_id) {
+		this.mch_id = mch_id;
+	}
+
+	public String getNonce_str() {
+		return nonce_str;
+	}
+
+	public void setNonce_str(String nonce_str) {
+		this.nonce_str = nonce_str;
+	}
+
+	public String getSign() {
+		return sign;
+	}
+
+	public void setSign(String sign) {
+		this.sign = sign;
+	}
+
+	public String getResult_code() {
+		return result_code;
+	}
+
+	public void setResult_code(String result_code) {
+		this.result_code = result_code;
+	}
+
+	public String getErr_code() {
+		return err_code;
+	}
+
+	public void setErr_code(String err_code) {
+		this.err_code = err_code;
+	}
+
+	public String getErr_code_des() {
+		return err_code_des;
+	}
+
+	public void setErr_code_des(String err_code_des) {
+		this.err_code_des = err_code_des;
+	}
+
+	public String getRecall() {
+		return recall;
+	}
+
+	public void setRecall(String recall) {
+		this.recall = recall;
+	}
+
+}

+ 307 - 102
kmall-common/src/main/java/com/kmall/common/utils/wechat/WechatUtil.java

@@ -53,6 +53,65 @@ public class WechatUtil {
     private static final String URL_PARAM_CONNECT_FLAG = "&";
 
     /**
+     * 菜单类型
+     *
+     * @author Scott
+     * @email
+     * @date 2016年11月15日 下午1:24:29
+     */
+    public enum WXTradeState {
+        /**
+         * 支付成功
+         */
+        SUCCESS("SUCCESS", "支付成功"),
+        /**
+         * 转入退款
+         */
+        REFUND("REFUND", "转入退款"),
+
+        /**
+         * 未支付
+         */
+        NOTPAY("NOTPAY", "未支付"),
+
+        /**
+         * 已关闭
+         */
+        CLOSED("CLOSED", "已关闭"),
+
+        /**
+         * 已撤销(付款码支付)
+         */
+        REVOKED("REVOKED", "已撤销"),
+
+        /**
+         * 用户支付中(付款码支付)
+         */
+        USERPAYING("USERPAYING", "用户支付中"),
+
+        /**
+         * 支付失败(付款码支付)
+         */
+        PAYERROR("PAYERROR", "支付失败");
+
+        private String code;
+        private String codeZn;
+
+        private WXTradeState(String code, String codeZn) {
+            this.code = code;
+            this.codeZn = codeZn;
+        }
+
+        public String getCode() {
+            return code;
+        }
+
+        public String getCodeZn() {
+            return codeZn;
+        }
+    }
+
+    /**
      * 方法描述:微信退款逻辑
      * 创建时间:2017年4月12日  上午11:04:25
      * 作者: xubo
@@ -66,12 +125,13 @@ public class WechatUtil {
         BigDecimal bdOrderMoney = new BigDecimal(orderMoney, MathContext.DECIMAL32);
         BigDecimal bdRefundMoney = new BigDecimal(refundMoney, MathContext.DECIMAL32);
         //构建请求参数
-        Map<Object, Object> params = buildRequsetMapParam(out_trade_no, bdOrderMoney, bdRefundMoney);
+        Map<Object, Object> params = buildRefundRequsetMapParam(out_trade_no, bdOrderMoney, bdRefundMoney);
         String mapToXml = MapUtils.convertMap2Xml(params);
         //请求微信
-        String reponseXml = sendSSLPostToWx(mapToXml, WechatConfig.getSslcsf());
-        WechatRefundApiResult result = (WechatRefundApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatRefundApiResult.class);
-        result.setOut_refund_no((String)params.get("out_refund_no"));
+        String reponseXml = sendRefundSSLPostToWx(mapToXml, WechatConfig.getSslcsf());
+        WechatRefundApiResult result =
+                (WechatRefundApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatRefundApiResult.class);
+        result.setOut_refund_no((String) params.get("out_refund_no"));
         return result;
     }
 
@@ -83,13 +143,14 @@ public class WechatUtil {
      * @param
      * @return
      */
-    private static Map<Object, Object> buildRequsetMapParam(String out_trade_no, BigDecimal bdOrderMoney, BigDecimal bdRefundMoney) {
+    private static Map<Object, Object> buildRefundRequsetMapParam(String out_trade_no, BigDecimal bdOrderMoney,
+                                                                  BigDecimal bdRefundMoney) {
         Map<Object, Object> params = new HashMap<Object, Object>();
         params.put("appid", CommonWxPayPropertiesBuilder.instance().getAppId());//微信分配的公众账号ID(企业号corpid即为此appId)
         params.put("mch_id", CommonWxPayPropertiesBuilder.instance().getMchId());//微信支付分配的商户号
         params.put("nonce_str", CharUtil.getRandomString(16));//随机字符串,不长于32位。推荐随机数生成算法
         params.put("out_trade_no", out_trade_no);//商户传给微信的订单号
-        params.put("out_refund_no", System.currentTimeMillis()+"");//商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
+        params.put("out_refund_no", System.currentTimeMillis() + "");//商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
         params.put("total_fee", bdOrderMoney.multiply(Constant.ONE_HUNDRED).intValue());//订单总金额,单位为分,只能为整数
         params.put("refund_fee", bdRefundMoney.multiply(Constant.ONE_HUNDRED).intValue());//退款总金额,订单总金额,单位为分,只能为整数
         params.put("op_user_id", CommonWxPayPropertiesBuilder.instance().getMchId());//操作员帐号, 默认为商户号
@@ -101,12 +162,21 @@ public class WechatUtil {
     }
 
     /**
-     * 请求微信https
+     * 请求退款微信
      **/
-    public static String sendSSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf) {
+    public static String sendRefundSSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf) {
         logger.info("*******退款(WX Request:" + mapToXml);
-        System.out.println("*******退款(WX Request:" + mapToXml);
-        HttpPost httPost = new HttpPost(CommonWxPayPropertiesBuilder.instance().getRefundUrl());
+        String xmlStr = sendSSLPostToWx(mapToXml, sslcsf, CommonWxPayPropertiesBuilder.instance().getRefundUrl());
+        logger.info("*******退款(WX Response:" + xmlStr);
+        return xmlStr;
+    }
+
+    /**
+     * 请求微信https
+     **/
+    private static String sendSSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf, String requestUrl) {
+
+        HttpPost httPost = new HttpPost(requestUrl);
         httPost.addHeader("Connection", "keep-alive");
         httPost.addHeader("Accept", "*/*");
         httPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
@@ -115,14 +185,18 @@ public class WechatUtil {
         httPost.addHeader("Cache-Control", "max-age=0");
         httPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
         httPost.setEntity(new StringEntity(mapToXml, "UTF-8"));
-        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
+        CloseableHttpClient httpClient = null;
+        if (sslcsf != null) {
+            httpClient = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
+        } else {
+            httpClient = HttpClients.createDefault();
+        }
+
         CloseableHttpResponse response = null;
         try {
             response = httpClient.execute(httPost);
             HttpEntity entity = response.getEntity();
             String xmlStr = EntityUtils.toString(entity, "UTF-8");
-            logger.info("*******退款(WX Response:" + xmlStr);
-            System.out.println("*******退款(WX Response:" + xmlStr);
             return xmlStr;
         } catch (Exception e) {
             logger.error(e.getMessage(), e);
@@ -171,59 +245,10 @@ public class WechatUtil {
             HttpEntity entity = response.getEntity();
             String xmlStr = EntityUtils.toString(entity, "UTF-8");
             System.out.println(xmlStr);
-            WechatRefundQueryResult result = (WechatRefundQueryResult) XmlUtil.xmlStrToBean(xmlStr, WechatRefundQueryResult.class);
+            WechatRefundQueryResult result =
+                    (WechatRefundQueryResult) XmlUtil.xmlStrToBean(xmlStr, WechatRefundQueryResult.class);
             result.setXmlStr(xmlStr);
-//            Map<String, Object> result = XmlUtil.xmlStrToMap(xmlStr);//.xmlStrToBean(xmlStr, WechatRefundApiResult.class);
-            return result;
-            //将信息保存到数据库
-        } catch (Exception e) {
-            logger.error(e.getMessage(), e);
-            return null;
-        } finally {
-            try {
-                if (response != null) {
-                    response.close();
-                }
-            } catch (IOException e) {
-                logger.error(e.getMessage(), e);
-            }
-        }
-    }
-
-
-    /**
-     * 方法描述:微信查询订单逻辑
-     * 创建时间:2018年11月02日  上午11:04:25
-     * 作者: huangyaqin
-     * @param
-     * @return
-     */
-    public static WechatRefundApiResult wxOrderQuery(String out_trade_no) {
-        Map<Object, Object> params = new HashMap<Object, Object>();
-        params.put("appid", CommonWxPayPropertiesBuilder.instance().getAppId());//微信分配的公众账号ID(企业号corpid即为此appId)
-        params.put("mch_id", CommonWxPayPropertiesBuilder.instance().getMchId());//微信支付分配的商户号
-        params.put("nonce_str", CharUtil.getRandomString(16));//随机字符串,不长于32位。推荐随机数生成算法
-        params.put("out_trade_no", out_trade_no);//商户侧传给微信的订单号
-        //签名前必须要参数全部写在前面
-        params.put("sign", arraySign(params, CommonWxPayPropertiesBuilder.instance().getPaySignKey()));//签名
-        String mapToXml = MapUtils.convertMap2Xml(params);
-        HttpPost httPost = new HttpPost(CommonWxPayPropertiesBuilder.instance().getOrderquery());
-        httPost.addHeader("Connection", "keep-alive");
-        httPost.addHeader("Accept", "*/*");
-        httPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
-        httPost.addHeader("Host", "api.mch.weixin.qq.com");
-        httPost.addHeader("X-Requested-With", "XMLHttpRequest");
-        httPost.addHeader("Cache-Control", "max-age=0");
-        httPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
-        httPost.setEntity(new StringEntity(mapToXml, "UTF-8"));
-        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(WechatConfig.getSslcsf()).build();
-        CloseableHttpResponse response = null;
-        try {
-            response = httpClient.execute(httPost);
-            HttpEntity entity = response.getEntity();
-            String xmlStr = EntityUtils.toString(entity, "UTF-8");
-            System.out.println("xmlStr : " + xmlStr);
-            WechatRefundApiResult result = (WechatRefundApiResult) XmlUtil.xmlStrToBean(xmlStr, WechatRefundApiResult.class);
+            //            Map<String, Object> result = XmlUtil.xmlStrToMap(xmlStr);//.xmlStrToBean(xmlStr, WechatRefundApiResult.class);
             return result;
             //将信息保存到数据库
         } catch (Exception e) {
@@ -305,32 +330,26 @@ public class WechatUtil {
      */
     public static String requestOnce(final String url, String data) {
         BasicHttpClientConnectionManager connManager;
-        connManager = new BasicHttpClientConnectionManager(
-                RegistryBuilder.<ConnectionSocketFactory>create()
-                        .register("http", PlainConnectionSocketFactory.getSocketFactory())
-                        .register("https", SSLConnectionSocketFactory.getSocketFactory())
-                        .build(),
-                null,
-                null,
-                null
-        );
-
-        HttpClient httpClient = HttpClientBuilder.create()
-                .setConnectionManager(connManager)
-                .build();
+        connManager = new BasicHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory>create()
+                                                                   .register("http", PlainConnectionSocketFactory
+                                                                           .getSocketFactory()).register("https",
+                                                                                                         SSLConnectionSocketFactory
+                                                                                                                 .getSocketFactory())
+                                                                   .build(), null, null, null);
+
+        HttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connManager).build();
 
         HttpPost httpPost = new HttpPost(url);
 
-        RequestConfig requestConfig = RequestConfig.custom()
-                .setSocketTimeout(5000)
-                .setConnectTimeout(5000)
-                .setConnectionRequestTimeout(10000).build();
+        RequestConfig requestConfig =
+                RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).setConnectionRequestTimeout(10000)
+                             .build();
 
         httpPost.setConfig(requestConfig);
 
         StringEntity postEntity = new StringEntity(data, "UTF-8");
         httpPost.addHeader("Content-Type", "text/xml");
-//        httpPost.addHeader("User-Agent", "wxpay sdk java v1.0 " + CommonWxPayPropertiesBuilder.instance().getMchId());
+        //        httpPost.addHeader("User-Agent", "wxpay sdk java v1.0 " + CommonWxPayPropertiesBuilder.instance().getMchId());
         httpPost.addHeader("User-Agent", "wxpay sdk java v1.0 " + "1517534731");
         httpPost.setEntity(postEntity);
 
@@ -358,28 +377,22 @@ public class WechatUtil {
     public static String requestOnceGet(final String url, Map params) {
         StringBuffer strtTotalURL = new StringBuffer(EMPTY);
         BasicHttpClientConnectionManager connManager;
-        connManager = new BasicHttpClientConnectionManager(
-                RegistryBuilder.<ConnectionSocketFactory>create()
-                        .register("http", PlainConnectionSocketFactory.getSocketFactory())
-                        .register("https", SSLConnectionSocketFactory.getSocketFactory())
-                        .build(),
-                null,
-                null,
-                null
-        );
-
-        HttpClient httpClient = HttpClientBuilder.create()
-                .setConnectionManager(connManager)
-                .build();
+        connManager = new BasicHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory>create()
+                                                                   .register("http", PlainConnectionSocketFactory
+                                                                           .getSocketFactory()).register("https",
+                                                                                                         SSLConnectionSocketFactory
+                                                                                                                 .getSocketFactory())
+                                                                   .build(), null, null, null);
+
+        HttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connManager).build();
         HttpGet httpGet = new HttpGet(url);
-        RequestConfig requestConfig = RequestConfig.custom()
-                .setSocketTimeout(5000)
-                .setConnectTimeout(5000)
-                .setConnectionRequestTimeout(10000).build();
+        RequestConfig requestConfig =
+                RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).setConnectionRequestTimeout(10000)
+                             .build();
 
         httpGet.setConfig(requestConfig);
         httpGet.addHeader("Content-Type", "text/xml");
-//        httpGet.addHeader("User-Agent", "wxpay sdk java v1.0 " + CommonWxPayPropertiesBuilder.instance().getMchId());
+        //        httpGet.addHeader("User-Agent", "wxpay sdk java v1.0 " + CommonWxPayPropertiesBuilder.instance().getMchId());
         httpGet.addHeader("User-Agent", "wxpay sdk java v1.0 " + "1517534731");
         if (strtTotalURL.indexOf("?") == -1) {
             strtTotalURL.append(url).append("?").append(getUrl(params, "UTF-8"));
@@ -436,6 +449,197 @@ public class WechatUtil {
     }
 
 
+    /**
+     * 调用付款码支付逻辑
+     *
+     * @param shop_name    门店名称
+     * @param orderBizType 订单业务类型
+     * @param attach       附加数据,该字段主要用于商户携带订单的自定义数据,如无可为null
+     * @param out_trade_no 商户订单编号
+     * @param orderMoney   订单总金额,单位:元
+     * @param ip           当前机器ip
+     * @param auth_code    扫码得到支付授权码
+     * @return 微信返回信息
+     */
+    public static WechatMicropayApiResult wxMicropay(String shop_name, String orderBizType, String attach,
+                                                     String out_trade_no, double orderMoney, String ip,
+                                                     String auth_code) {
+        //初始化请求微信服务器的配置信息包括appid密钥等
+        //转换金钱格式
+        BigDecimal bdOrderMoney = new BigDecimal(orderMoney, MathContext.DECIMAL32);
+        //构建请求参数
+        Map<Object, Object> params =
+                buildMicropayRequsetMapParam(shop_name, orderBizType, attach, out_trade_no, bdOrderMoney, ip,
+                                             auth_code);
+        String mapToXml = MapUtils.convertMap2Xml(params);
+        //请求微信
+        String reponseXml = sendMicropaySSLPostToWx(mapToXml);
+        WechatMicropayApiResult result =
+                (WechatMicropayApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatMicropayApiResult.class);
+        if ("SUCCESS".equals(result.getReturn_code()) && "OK".equals(result.getReturn_msg())) {
+            //支付成功
+            if ("SUCCESS".equals(result.getResult_code())) {
+                result.setTrade_state(WXTradeState.SUCCESS.getCode());
+            } else if ("FAIL".equals(result.getResult_code())) {
+                //支付中
+                if ("USERPAYING".equals(result.getErr_code()) || "SYSTEMERROR".equals(result.getErr_code()) ||
+                    "BANKERROR".equals(result.getErr_code())) {
+                    result.setTrade_state(WXTradeState.USERPAYING.getCode());
+                    //支付失败
+                } else {
+                    result.setTrade_state(WXTradeState.PAYERROR.getCode());
+                }
+            }
+        }
+        return result;
+    }
+
+
+    public static WechatReverseApiResult wxReverse(String out_trade_no) {
+        //初始化请求微信服务器的配置信息包括appid密钥等
+        //构建请求参数
+        Map<Object, Object> params = buildReverseRequsetMapParam(out_trade_no);
+        String mapToXml = MapUtils.convertMap2Xml(params);
+        //请求微信
+        String reponseXml = sendReverseSSLPostToWx(mapToXml, WechatConfig.getSslcsf());
+        WechatReverseApiResult result =
+                (WechatReverseApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatReverseApiResult.class);
+        return result;
+    }
+
+
+    /**
+     * 方法描述:微信查询订单逻辑
+     * 创建时间:2018年11月02日  上午11:04:25
+     * 作者: huangyaqin
+     *
+     * @param
+     * @return
+     */
+    public static WechatRefundApiResult wxOrderQuery(String out_trade_no) {
+        //初始化请求微信服务器的配置信息包括appid密钥等
+        //构建请求参数
+        Map<Object, Object> params = buildQueryRequsetMapParam(out_trade_no);
+        String mapToXml = MapUtils.convertMap2Xml(params);
+        //请求微信
+        String reponseXml = sendQuerySSLPostToWx(mapToXml);
+        WechatRefundApiResult result =
+                (WechatRefundApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatRefundApiResult.class);
+        return result;
+    }
+
+    /**
+     * 绑定提交付款码支付请求输入参数
+     *
+     * @param shop_name    门店名称
+     * @param orderBizType 订单业务类型
+     * @param attach       附加数据,该字段主要用于商户携带订单的自定义数据,如无可为null
+     * @param out_trade_no 商户订单编号
+     * @param orderMoney   订单总金额,单位:元
+     * @param ip           当前机器ip
+     * @param auth_code    扫码得到支付授权码
+     * @return 提交付款码支付请求输入参数
+     */
+    private static Map<Object, Object> buildMicropayRequsetMapParam(String shop_name, String orderBizType,
+                                                                    String attach, String out_trade_no,
+                                                                    BigDecimal orderMoney, String ip,
+                                                                    String auth_code) {
+        Map<Object, Object> params = new HashMap<Object, Object>();
+        params.put("appid", CommonWxPayPropertiesBuilder.instance().getAppId());//微信分配的公众账号ID(企业号corpid即为此appId)
+        params.put("mch_id", CommonWxPayPropertiesBuilder.instance().getMchId());//微信支付分配的商户号
+        params.put("nonce_str", CharUtil.getRandomString(16));//随机字符串,不长于32位。推荐随机数生成算法
+
+        String orderBizTypeZn = "普通货物";
+        if ("00".equals(orderBizType)) {
+            orderBizTypeZn = "保税备货";
+        } else if ("02".equals(orderBizType)) {
+            orderBizTypeZn = "保税展示补货";
+        } else if ("10".equals(orderBizType)) {
+            orderBizTypeZn = "保税展示跨境";
+        }
+        params.put("body", shop_name + "-" + orderBizTypeZn);//商品简单描述,不长于128位
+
+        if (StringUtils.isNotEmpty(attach)) {
+            params.put("attach", attach);//附加数据,不长于127位,该字段主要用于商户携带订单的自定义数据
+        }
+
+        params.put("out_trade_no", out_trade_no);//商户传给微信的订单号
+        params.put("total_fee", orderMoney.multiply(Constant.ONE_HUNDRED).intValue());//订单总金额,单位为分,只能为整数
+        params.put("spbill_create_ip", ip);//当前机器ip
+        params.put("auth_code", auth_code);//扫码支付授权码,设备读取用户微信中的条码或者二维码信息
+        //签名前必须要参数全部写在前面
+        params.put("sign", arraySign(params, CommonWxPayPropertiesBuilder.instance().getPaySignKey()));//签名
+        return params;
+    }
+
+
+    /**
+     * 绑定撤销订单求输入参数
+     *
+     * @param out_trade_no 订单编号(发送到微信的编号)
+     * @return 撤销订单求输入参数
+     */
+    private static Map<Object, Object> buildReverseRequsetMapParam(String out_trade_no) {
+        Map<Object, Object> params = new HashMap<Object, Object>();
+        params.put("appid", CommonWxPayPropertiesBuilder.instance().getAppId());//微信分配的公众账号ID(企业号corpid即为此appId)
+        params.put("mch_id", CommonWxPayPropertiesBuilder.instance().getMchId());//微信支付分配的商户号
+        params.put("out_trade_no", out_trade_no);//商户传给微信的订单号
+        params.put("nonce_str", CharUtil.getRandomString(16));//随机字符串,不长于32位。推荐随机数生成算法
+        //签名前必须要参数全部写在前面
+        params.put("sign", arraySign(params, CommonWxPayPropertiesBuilder.instance().getPaySignKey()));//签名
+        return params;
+    }
+
+
+    /**
+     * 绑定查询订单求输入参数
+     *
+     * @param out_trade_no 订单编号(发送到微信的编号)
+     * @return 查询订单求输入参数
+     */
+    private static Map<Object, Object> buildQueryRequsetMapParam(String out_trade_no) {
+        Map<Object, Object> params = new HashMap<Object, Object>();
+        params.put("appid", CommonWxPayPropertiesBuilder.instance().getAppId());//微信分配的公众账号ID(企业号corpid即为此appId)
+        params.put("mch_id", CommonWxPayPropertiesBuilder.instance().getMchId());//微信支付分配的商户号
+        params.put("out_trade_no", out_trade_no);//商户传给微信的订单号
+        params.put("nonce_str", CharUtil.getRandomString(16));//随机字符串,不长于32位。推荐随机数生成算法
+        //签名前必须要参数全部写在前面
+        params.put("sign", arraySign(params, CommonWxPayPropertiesBuilder.instance().getPaySignKey()));//签名
+        return params;
+    }
+
+    /**
+     * 请求退款微信
+     **/
+    private static String sendMicropaySSLPostToWx(String mapToXml) {
+        logger.info("*******付款码支付(WX Request:" + mapToXml);
+        String xmlStr = sendSSLPostToWx(mapToXml, null, CommonWxPayPropertiesBuilder.instance().getMicropayUrl());
+        logger.info("*******付款码支付(WX Response:" + xmlStr);
+        return xmlStr;
+    }
+
+    /**
+     * 请求撤销订单微信
+     **/
+    private static String sendReverseSSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf) {
+        logger.info("*******撤销订单(WX Request:" + mapToXml);
+        String xmlStr = sendSSLPostToWx(mapToXml, sslcsf, CommonWxPayPropertiesBuilder.instance().getReverseUrl());
+        logger.info("*******撤销订单(WX Response:" + xmlStr);
+        return xmlStr;
+    }
+
+
+    /**
+     * 请求查询订单微信
+     **/
+    private static String sendQuerySSLPostToWx(String mapToXml) {
+        logger.info("*******查询订单(WX Request:" + mapToXml);
+        String xmlStr = sendSSLPostToWx(mapToXml, null, CommonWxPayPropertiesBuilder.instance().getOrderquery());
+        logger.info("*******查询订单(WX Response:" + xmlStr);
+        return xmlStr;
+    }
+
+
     public static void main(String[] args) throws Exception {
         Map<Object, Object> parame = new TreeMap<Object, Object>();
         parame.put("mch_id", ResourceUtil.getConfigByName("\\conf\\wx-mp", "wx.mchId"));//
@@ -446,7 +650,8 @@ public class WechatUtil {
 
         String xml = MapUtils.convertMap2Xml(parame);
         logger.info("xml:" + xml);
-        Map<String, Object> resultUn = XmlUtil.xmlStrToMap(WechatUtil.requestOnce("https://apitest.mch.weixin.qq.com/sandboxnew/pay/getsignkey", xml));
+        Map<String, Object> resultUn = XmlUtil.xmlStrToMap(
+                WechatUtil.requestOnce("https://apitest.mch.weixin.qq.com/sandboxnew/pay/getsignkey", xml));
         System.out.print(resultUn);
     }
 }

+ 34 - 0
kmall-schedule/src/main/java/com/kmall/schedule/dao/OrderWXPayRecordMapper.java

@@ -0,0 +1,34 @@
+package com.kmall.schedule.dao;
+
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+@Component
+public interface OrderWXPayRecordMapper {
+
+    /**
+     * 根据交易状态查询支付记录
+     *
+     * @param tradeStates
+     * @return 支付记录
+     */
+    List<Map> queryRecordList(List<String> tradeStates);
+
+    /**
+     * 根据订单编号查询支付记录
+     *
+     * @param out_trade_no 订单编号
+     * @return 支付记录
+     */
+    List<Map> getRecordsByOutTradeNo(String out_trade_no);
+
+    /**
+     * 修改记录
+     *
+     * @param params
+     * @return
+     */
+    int update(Map params);
+}

+ 8 - 0
kmall-schedule/src/main/java/com/kmall/schedule/dao/QzOrderMapper.java

@@ -54,4 +54,12 @@ public interface QzOrderMapper {
 
     void updateReceiptOrderByCommentCount();
 
+
+    /**
+     * 根据订单编号查询
+     * @param orderSn 订单编号
+     * @return
+     */
+    Map queryOrder(String orderSn);
+
 }

+ 183 - 68
kmall-schedule/src/main/java/com/kmall/schedule/service/QzOrderService.java

@@ -1,18 +1,13 @@
 package com.kmall.schedule.service;
 
-import com.kmall.common.utils.Constant;
-import com.kmall.common.utils.wechat.ReaderXmlForDOM4J;
-import com.kmall.common.utils.wechat.WechatRefundApiResult;
-import com.kmall.common.utils.wechat.WechatRefundQueryResult;
-import com.kmall.common.utils.wechat.WechatUtil;
+import com.kmall.common.utils.*;
+import com.kmall.common.utils.wechat.*;
+import com.kmall.schedule.dao.OrderWXPayRecordMapper;
 import com.kmall.schedule.dao.QzGroupMapper;
 import com.kmall.schedule.dao.QzOrderMapper;
 import com.kmall.common.dao.TemplateConfDao;
 import com.kmall.common.entity.TemplateConfVo;
 import com.kmall.schedule.quartz.OrderTask;
-import com.kmall.common.utils.DateUtils;
-import com.kmall.common.utils.MapUtils;
-import com.kmall.common.utils.StringUtils;
 import com.kmall.common.utils.wxtemplate.TemplateData;
 import com.kmall.common.utils.wxtemplate.WxTemplate;
 import com.kmall.common.utils.wxtemplate.WxTemplateUtil;
@@ -29,6 +24,7 @@ import java.util.*;
 
 /**
  * 微信提醒任务
+ *
  * @author zhouzhengde(CN)
  * @date 2017/12/4.
  */
@@ -41,6 +37,8 @@ public class QzOrderService {
     private QzGroupMapper qzGroupMapper;
     @Autowired
     private QzOrderMapper qzOrderMapper;
+    @Autowired
+    private OrderWXPayRecordMapper orderWXPayRecordMapper;
 
     /**
      * todo 一期暂时不实现团购
@@ -49,7 +47,8 @@ public class QzOrderService {
     @Transactional
     public void groupProgressRemind() {
         logger.info(">>>>>>>>>>>>>>>>>>>>groupProgressRemind is start ");
-        TemplateConfVo templateConfVo = templateConfDao.queryByTypeId(4); //  模板类型 1订单付款成功 2团购成功 3拼团失败通知 4拼团进度 5 6 7订单配送 8订单评价提醒
+        TemplateConfVo templateConfVo =
+                templateConfDao.queryByTypeId(4); //  模板类型 1订单付款成功 2团购成功 3拼团失败通知 4拼团进度 5 6 7订单配送 8订单评价提醒
         if (null == templateConfVo) {
             return;
         }
@@ -71,7 +70,7 @@ public class QzOrderService {
                 }
                 WxTemplate tem = new WxTemplate();
                 tem.setTemplate_id(templateConfVo.getTemplateId());
-//                tem.setTopcolor("#00DD00");
+                //                tem.setTopcolor("#00DD00");
                 tem.setTouser(open_id);
                 tem.setPage("/pages/groupDetail/groupDetail?id=" + group_id);
                 tem.setForm_id(form_id);
@@ -87,7 +86,9 @@ public class QzOrderService {
                 long second = (time - hour * 3600 - minite * 60);
                 String body = hour + "时" + minite + "分" + second + "秒";
                 paras.add(new TemplateData("keyword3", body, "#000000"));
-                paras.add(new TemplateData("keyword4", retail_min_price.setScale(2, BigDecimal.ROUND_HALF_DOWN).toString() + "元", "#000000"));
+                paras.add(new TemplateData("keyword4",
+                                           retail_min_price.setScale(2, BigDecimal.ROUND_HALF_DOWN).toString() + "元",
+                                           "#000000"));
                 paras.add(new TemplateData("keyword5", templateConfVo.getDesc(), "#000000"));
                 tem.setData(paras);
                 WxTemplateUtil.sendMessage(tem);
@@ -103,7 +104,8 @@ public class QzOrderService {
     @Transactional
     public void pastGroupRemind() {
         logger.info(">>>>>>>>>>>>>>>>>>>>pastGroupRemind is start ");
-        TemplateConfVo templateConfVo = templateConfDao.queryByTypeId(3); //  模板类型 1订单付款成功 2团购成功 3拼团失败通知 4拼团进度 5 6 7订单配送 8订单评价提醒
+        TemplateConfVo templateConfVo =
+                templateConfDao.queryByTypeId(3); //  模板类型 1订单付款成功 2团购成功 3拼团失败通知 4拼团进度 5 6 7订单配送 8订单评价提醒
         if (null == templateConfVo) {
             return;
         }
@@ -124,7 +126,7 @@ public class QzOrderService {
                 }
                 WxTemplate tem = new WxTemplate();
                 tem.setTemplate_id(templateConfVo.getTemplateId());
-//                tem.setTopcolor("#00DD00");
+                //                tem.setTopcolor("#00DD00");
                 tem.setTouser(open_id);
                 tem.setPage("/pages/groupDetail/groupDetail?id=" + group_id);
                 tem.setForm_id(form_id);
@@ -151,7 +153,8 @@ public class QzOrderService {
     @Transactional
     public void orderUnEvaluateRemind() {
         logger.info(">>>>>>>>>>>>>>>>>>>>orderUnEvaluateRemind is start ");
-        TemplateConfVo templateConfVo = templateConfDao.queryByTypeId(8); //  模板类型 1订单付款成功 2团购成功 3拼团失败通知 4拼团进度 5 6 7订单配送 8订单评价提醒
+        TemplateConfVo templateConfVo =
+                templateConfDao.queryByTypeId(8); //  模板类型 1订单付款成功 2团购成功 3拼团失败通知 4拼团进度 5 6 7订单配送 8订单评价提醒
         if (null == templateConfVo) {
             return;
         }
@@ -169,7 +172,7 @@ public class QzOrderService {
                 }
                 WxTemplate tem = new WxTemplate();
                 tem.setTemplate_id(templateConfVo.getTemplateId());
-//                tem.setTopcolor("#00DD00");
+                //                tem.setTopcolor("#00DD00");
                 tem.setTouser(open_id);
                 tem.setPage("/pages/ucenter/orderDetail/orderDetail?id=" + id);
                 tem.setForm_id(form_id);
@@ -224,11 +227,12 @@ public class QzOrderService {
                 String order_id = MapUtils.getString("order_id", map);
                 WechatRefundQueryResult result = WechatUtil.wxRefundquery(out_trade_no);
                 if (result.getReturn_code().equalsIgnoreCase("SUCCESS")) {
-                    if(result.getResult_code().equalsIgnoreCase("SUCCESS")) {
+                    if (result.getResult_code().equalsIgnoreCase("SUCCESS")) {
                         Map refundRaram = new HashMap();
                         int msgCount = Integer.parseInt(result.getRefund_count());
                         for (int i = 0; i < msgCount; i++) {
-                            WechatRefundQueryResult querySuccessResponseDto = ReaderXmlForDOM4J.parse(result.getXmlStr(), i);
+                            WechatRefundQueryResult querySuccessResponseDto =
+                                    ReaderXmlForDOM4J.parse(result.getXmlStr(), i);
                             if (result.getReturn_code().equalsIgnoreCase("SUCCESS")) {
                                 if (result.getResult_code().equalsIgnoreCase("SUCCESS")) {
                                     result.setRefund_success_time(querySuccessResponseDto.getRefund_success_time());
@@ -244,7 +248,9 @@ public class QzOrderService {
                                     refundRaram.put("refundTime", successTime);
                                     refundRaram.put("outRefundNo", result.getOut_refund_no());
                                     refundRaram.put("refundId", result.getRefund_id());
-                                    refundRaram.put("refundMoney", BigDecimal.valueOf(Long.valueOf(result.getRefund_fee())).divide(Constant.ONE_HUNDRED));
+                                    refundRaram.put("refundMoney",
+                                                    BigDecimal.valueOf(Long.valueOf(result.getRefund_fee()))
+                                                              .divide(Constant.ONE_HUNDRED));
                                     if (result.getRefund_status().equalsIgnoreCase("SUCCESS")) {
                                         refundRaram.put("refundStatus", 2);
                                         refundRaram.put("wechat_refund_status_des", "退款成功");
@@ -271,14 +277,15 @@ public class QzOrderService {
                         orderRaram.put("orderId", order_id);
                         orderRaram.put("payTransactionId", result.getTransaction_id());
                         qzOrderMapper.updateOrderInfo(orderRaram);
-                    }else{
-                        logger.info(">>>>>>>>>>>>>>>>>>>>refundUpdate 微信退款查询接口返回失败信息:code 【"+result.getErr_code()+"】,des【"+result.getErr_code_des()+"】");
+                    } else {
+                        logger.info(">>>>>>>>>>>>>>>>>>>>refundUpdate 微信退款查询接口返回失败信息:code 【" + result.getErr_code() +
+                                    "】,des【" + result.getErr_code_des() + "】");
                     }
-                }else {
-                    logger.info(">>>>>>>>>>>>>>>>>>>>refundUpdate 微信退款查询接口调用失败: "+result.getReturn_msg());
+                } else {
+                    logger.info(">>>>>>>>>>>>>>>>>>>>refundUpdate 微信退款查询接口调用失败: " + result.getReturn_msg());
                 }
             }
-        }else{
+        } else {
             logger.info(">>>>>>>>>>>>>>>>>>>>refundUpdate 未查到退款数据 ");
         }
         logger.info(">>>>>>>>>>>>>>>>>>>>refundUpdate is end ");
@@ -307,8 +314,10 @@ public class QzOrderService {
                 Date nowDate = new Date();
                 WechatRefundApiResult result = WechatUtil.wxOrderQuery(out_trade_no);
                 if (result.getReturn_code().equalsIgnoreCase("SUCCESS")) {
-                    if(result.getResult_code().equalsIgnoreCase("SUCCESS") && result.getTrade_state().equalsIgnoreCase("SUCCESS")) {
-                        Date successTime = DateUtils.convertStringToDate(result.getTime_end(),DateUtils.DATE_TIME_PATTERN_YYYY_MM_DD_HH_MM_SS);
+                    if (result.getResult_code().equalsIgnoreCase("SUCCESS") &&
+                        result.getTrade_state().equalsIgnoreCase("SUCCESS")) {
+                        Date successTime = DateUtils.convertStringToDate(result.getTime_end(),
+                                                                         DateUtils.DATE_TIME_PATTERN_YYYY_MM_DD_HH_MM_SS);
 
                         Map orderRaram = new HashMap();
                         orderRaram.put("payStatus", 2);//已支付
@@ -317,35 +326,140 @@ public class QzOrderService {
                         orderRaram.put("payTime", successTime);
                         orderRaram.put("orderId", orderId);
                         qzOrderMapper.updateOrderInfo(orderRaram);
-                    }else if(result.getResult_code().equalsIgnoreCase("SUCCESS")
-                            && result.getTrade_state().equalsIgnoreCase("NOTPAY")) {//订单未支付
+                    } else if (result.getResult_code().equalsIgnoreCase("SUCCESS") &&
+                               result.getTrade_state().equalsIgnoreCase("NOTPAY")) {//订单未支付
                         Map orderRaram = new HashMap();
-                        if(getDateBetween(addTime,nowDate) >= 15){//订单下单时间超过15分钟直接取消订单
+                        if (getDateBetween(addTime, nowDate) >= 15) {//订单下单时间超过15分钟直接取消订单
                             orderRaram.put("payStatus", 0);//支付状态未支付
                             orderRaram.put("orderStatus", 101);//订单状态已取消
                             Map param = new HashMap();
                             param.put("id", storeRelaId);
                             param.put("stock_num", stock_num + number);
                             qzOrderMapper.updateStockNum(param);
-                        }else{
+                        } else {
                             orderRaram.put("payStatus", 0);//支付状态未支付
                             orderRaram.put("orderStatus", 0);//订单状态未支付
                         }
                         orderRaram.put("orderId", orderId);
                         qzOrderMapper.updateOrderInfo(orderRaram);
-                    }else{
-                        logger.info(">>>>>>>>>>>>>>>>>>>>orderQueryUpdate 微信查询接口返回失败信息:code 【"+result.getErr_code()+"】,des【"+result.getErr_code_des()+"】");
+                    } else {
+                        logger.info(">>>>>>>>>>>>>>>>>>>>orderQueryUpdate 微信查询接口返回失败信息:code 【" + result.getErr_code() +
+                                    "】,des【" + result.getErr_code_des() + "】");
                     }
-                }else {
-                    logger.info(">>>>>>>>>>>>>>>>>>>>orderQueryUpdate 微信查询接口调用失败: "+result.getReturn_msg());
+                } else {
+                    logger.info(">>>>>>>>>>>>>>>>>>>>orderQueryUpdate 微信查询接口调用失败: " + result.getReturn_msg());
                 }
             }
-        }else{
+        } else {
             logger.info(">>>>>>>>>>>>>>>>>>>>orderQueryUpdate 未查到订单数据 ");
         }
         logger.info(">>>>>>>>>>>>>>>>>>>>orderQueryUpdate is end ");
     }
 
+
+    /**
+     * 查询付款码支付记录的支付状态
+     */
+    @Transactional
+    public void orderMicropayQueryUpdate() {
+        logger.info(">>>>>>>>>>>>>>>>>>>>查询付款码支付记录的支付状态开始<<<<<<<<<<<<<<<<<<<<<<<");
+        // 获取交易状态是未支付,支付中和支付失败3种状态的付款码支付记录
+        List<String> tradeStates = new ArrayList<>();
+        tradeStates.add(WechatUtil.WXTradeState.NOTPAY.getCode());
+        tradeStates.add(WechatUtil.WXTradeState.USERPAYING.getCode());
+        tradeStates.add(WechatUtil.WXTradeState.PAYERROR.getCode());
+        List<Map> records = orderWXPayRecordMapper.queryRecordList(tradeStates);
+        if (null != records && records.size() > 0) {
+            for (Map map : records) {
+                String out_trade_no_wx = MapUtils.getString("out_trade_no_wx", map);
+                String out_trade_no = MapUtils.getString("out_trade_no", map);
+                Integer id = MapUtils.getInteger("id", map);
+
+                WechatRefundApiResult result = WechatUtil.wxOrderQuery(out_trade_no_wx);
+                if ("SUCCESS".equals(result.getReturn_code()) && "SUCCESS".equals(result.getResult_code())) {
+                    Map recordRaram = new HashMap();
+                    recordRaram.put("id", id);
+                    recordRaram.put("trade_state", result.getTrade_state());
+                    //查询到支付成功
+                    if (WechatUtil.WXTradeState.SUCCESS.getCode().equals(result.getTrade_state())) {
+                        recordRaram.put("result_code", result.getTrade_state());
+                        recordRaram.put("err_code", "");
+                        recordRaram.put("err_code_des", "");
+                        recordRaram.put("openid", result.getOpenid());
+                        recordRaram.put("is_subscribe", result.getIs_subscribe());
+                        recordRaram.put("trade_type", result.getTrade_type());
+                        recordRaram.put("fee_type", result.getFee_type());
+                        recordRaram.put("total_fee", result.getTotal_fee());
+                        recordRaram.put("transaction_id", result.getTransaction_id());
+                        recordRaram.put("attach", result.getAttach());
+                        recordRaram.put("time_end", result.getTime_end());
+
+                        //修改订单状态
+                        Map order = qzOrderMapper.queryOrder(out_trade_no);
+                        if (MapUtils.getInteger("order_status", order) == 201) {
+                            logger.info(">>>>>>>>>>>>>>>>>>>>orderWXPayRecordQueryUpdate 此订单已付款: " + out_trade_no);
+                        } else if (MapUtils.getInteger("order_status", order) == 301) {
+                            logger.info(">>>>>>>>>>>>>>>>>>>>orderWXPayRecordQueryUpdate 此订单已完成: " + out_trade_no);
+                        } else if (MapUtils.getInteger("order_status", order) == 101) {
+                            logger.info(">>>>>>>>>>>>>>>>>>>>orderWXPayRecordQueryUpdate 此订单已取消: " + out_trade_no);
+                        } else if (MapUtils.getInteger("order_status", order) == 102) {
+                            logger.info(">>>>>>>>>>>>>>>>>>>>orderWXPayRecordQueryUpdate 此订单已删除: " + out_trade_no);
+                        } else {
+                            Map orderRaram = new HashMap();
+                            orderRaram.put("payStatus", 2);//已支付
+                            orderRaram.put("orderStatus", 201);//已支付
+                            orderRaram.put("payTime", new Date());
+                            orderRaram.put("orderId", MapUtils.getInteger("id", order));
+                            qzOrderMapper.updateOrderInfo(orderRaram);
+                            logger.info(">>>>>>>>>>>>>>>>>>>>orderWXPayRecordQueryUpdate 订单:" + out_trade_no +
+                                        "支付成功,修改支付状态");
+
+                            //查询当前订单所有的支付记录
+                            List<Map> orderWXPayRecordEntitys =
+                                    orderWXPayRecordMapper.getRecordsByOutTradeNo(out_trade_no);
+                            for (Map orderWXPayRecordTemp : orderWXPayRecordEntitys) {
+                                //查询出来的记录不等于当前记录,并且未撤销,未关闭时,撤销订单
+                                Integer orderWXPayRecordTemp_id = MapUtils.getInteger("id", orderWXPayRecordTemp);
+                                String orderWXPayRecordTemp_tradeState =
+                                        MapUtils.getString("trade_state", orderWXPayRecordTemp);
+                                String orderWXPayRecordTemp_outTradeNoWX =
+                                        MapUtils.getString("out_trade_no_wx", orderWXPayRecordTemp);
+                                if (orderWXPayRecordTemp_id != id && (!WechatUtil.WXTradeState.REVOKED.getCode()
+                                                                                                      .equals(orderWXPayRecordTemp_tradeState) ||
+                                                                      !WechatUtil.WXTradeState.CLOSED.getCode()
+                                                                                                     .equals(orderWXPayRecordTemp_tradeState))) {
+
+                                    logger.info(">>>>>>>>>>>>>>>>>>>>orderWXPayRecordQueryUpdate 订单:" +
+                                                orderWXPayRecordTemp_outTradeNoWX + "支付失败,调用撤销订单接口开始");
+                                    WechatUtil.wxReverse(orderWXPayRecordTemp_outTradeNoWX);
+                                    logger.info(">>>>>>>>>>>>>>>>>>>>orderWXPayRecordQueryUpdate 订单:" +
+                                                orderWXPayRecordTemp_outTradeNoWX + "支付失败,调用撤销订单接口结束");
+                                }
+                            }
+
+                        }
+                        //查询到支付失败,撤销订单
+                    } else if (WechatUtil.WXTradeState.PAYERROR.getCode().equals(result.getTrade_state())) {
+                        logger.info(">>>>>>>>>>>>>>>>>>>>orderWXPayRecordQueryUpdate 订单:" + out_trade_no_wx +
+                                    "支付失败,调用撤销订单接口开始");
+                        WechatUtil.wxReverse(out_trade_no_wx);
+                        logger.info(">>>>>>>>>>>>>>>>>>>>orderWXPayRecordQueryUpdate 订单:" + out_trade_no_wx +
+                                    "支付失败,调用撤销订单接口结束");
+                    }
+                    recordRaram.put("mod_time", new Date());
+                    orderWXPayRecordMapper.update(recordRaram);
+
+                } else {
+                    logger.info(
+                            ">>>>>>>>>>>>>>>>>>>>orderWXPayRecordQueryUpdate 微信查询接口调用失败: " + result.getReturn_msg());
+                }
+            }
+        } else {
+            logger.info(">>>>>>>>>>>>>>>>>>>>orderWXPayRecordQueryUpdate 未查到需要调用接口的支付记录数据 ");
+        }
+        logger.info(">>>>>>>>>>>>>>>>>>>>查询付款码支付记录的支付状态 结束<<<<<<<<<<<<<<<<<<<<<<<");
+    }
+
     @Transactional
     public void shipmentOrderAutoTakeGoods() {
         logger.info(">>>>>>>>>>>>>>>>>>>>shipmentOrderAutoTakeGoods is start ");
@@ -353,18 +467,18 @@ public class QzOrderService {
         // 查询门店业务发货后7天的订单
         List<Map> shipmentOrderList = qzOrderMapper.queryShipmentOrderList();
         if (null != shipmentOrderList && shipmentOrderList.size() > 0) {
-            for (Map map:shipmentOrderList) {
+            for (Map map : shipmentOrderList) {
                 Map orderMap = new HashMap();
-                orderMap.put("orderId",MapUtils.getLong("orderId",map));
+                orderMap.put("orderId", MapUtils.getLong("orderId", map));
                 qzOrderMapper.updateShipmentOrder(orderMap);
             }
         }
         //查询保税备货发货后7天的订单
         List<Map> shipmentBondedOrderList = qzOrderMapper.queryShipmentBondedOrderList();
         if (null != shipmentBondedOrderList && shipmentBondedOrderList.size() > 0) {
-            for (Map map:shipmentBondedOrderList) {
+            for (Map map : shipmentBondedOrderList) {
                 Map orderMap = new HashMap();
-                orderMap.put("orderId",MapUtils.getLong("orderId",map));
+                orderMap.put("orderId", MapUtils.getLong("orderId", map));
                 qzOrderMapper.updateShipmentOrder(orderMap);
             }
         }
@@ -389,17 +503,17 @@ public class QzOrderService {
                 Map param = new HashMap();
                 param.put("userId", userId);
                 param.put("orderId", orderId);
-                param.put("valueId",goodsId);
-                param.put("typeId",0);
-                param.put("productId",productId);
-                param.put("goodsSpecificationNameValue",goodsSpecificationNameValue);
-                param.put("status","1");
-                param.put("content","默认好评");
-                param.put("evalLevel",5);
-                param.put("goodsLevel",5);
-                param.put("valueName",goodsName);
-                param.put("createTime",new Date());
-                param.put("modTime",new Date());
+                param.put("valueId", goodsId);
+                param.put("typeId", 0);
+                param.put("productId", productId);
+                param.put("goodsSpecificationNameValue", goodsSpecificationNameValue);
+                param.put("status", "1");
+                param.put("content", "默认好评");
+                param.put("evalLevel", 5);
+                param.put("goodsLevel", 5);
+                param.put("valueName", goodsName);
+                param.put("createTime", new Date());
+                param.put("modTime", new Date());
                 qzOrderMapper.insertComment(param);//新增评论
             }
             qzOrderMapper.updateReceiptOrderByCommentCount();//修改评论数量
@@ -408,41 +522,42 @@ public class QzOrderService {
 
     }
 
-    public long getDateBetween(Date begin,Date end){
+    public long getDateBetween(Date begin, Date end) {
         SimpleDateFormat dfs = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
-        long between = (end.getTime() - begin.getTime())/1000;
+        long between = (end.getTime() - begin.getTime()) / 1000;
 
-        long min = between/60;
+        long min = between / 60;
 
         return min;
     }
+
     public static void main(String[] args) {
 
         SimpleDateFormat dfs = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
-        long between = (new Date().getTime() - DateUtils.strToDate("2018-11-16 09:30:12").getTime())/1000;
+        long between = (new Date().getTime() - DateUtils.strToDate("2018-11-16 09:30:12").getTime()) / 1000;
 
-        long min = between/60;
+        long min = between / 60;
         System.out.println(min);
-//        Calendar calendar = Calendar.getInstance();
-//        calendar.add(Calendar.DAY_OF_MONTH, 3);
-//
-//        long time = (calendar.getTime().getTime() - System.currentTimeMillis()) / 1000;
-//        System.out.println(calendar.getTime().getTime());
-//        System.out.println(System.currentTimeMillis());
-//        long hour = time / 3600;
-//        long minite = time / 60 % 60;
-//        long second = (time - hour * 3600 - minite * 60);
-//
-//        String body = hour + "时" + minite + "分" + second + "秒";
-//        System.out.println(body);
+        //        Calendar calendar = Calendar.getInstance();
+        //        calendar.add(Calendar.DAY_OF_MONTH, 3);
+        //
+        //        long time = (calendar.getTime().getTime() - System.currentTimeMillis()) / 1000;
+        //        System.out.println(calendar.getTime().getTime());
+        //        System.out.println(System.currentTimeMillis());
+        //        long hour = time / 3600;
+        //        long minite = time / 60 % 60;
+        //        long second = (time - hour * 3600 - minite * 60);
+        //
+        //        String body = hour + "时" + minite + "分" + second + "秒";
+        //        System.out.println(body);
 
         long currentTime = System.currentTimeMillis() + 2 * 60 * 60 * 1000;
         Date date = new Date(currentTime);
         DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        String nowTime="";
-        nowTime= df.format(date);
+        String nowTime = "";
+        nowTime = df.format(date);
         System.out.println(nowTime);
 
         Date successTime = DateUtils.strToDate("2018-11-02 14:57:12.0");

+ 46 - 0
kmall-schedule/src/main/resources/mybatis/mapper/OrderWXPayRecordMapper.xml

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="com.kmall.schedule.dao.OrderWXPayRecordMapper">
+    <update id="update" parameterType="map">
+        update mall_order_wxpay_record
+        <set>
+            <if test="return_code != null">`return_code` = #{return_code}, </if>
+            <if test="return_msg != null">`return_msg` = #{return_msg}, </if>
+            <if test="result_code != null">`result_code` = #{result_code}, </if>
+            <if test="err_code != null">`err_code` = #{err_code}, </if>
+            <if test="err_code_des != null">`err_code_des` = #{err_code_des}, </if>
+            <if test="openid != null">`openid` = #{openid}, </if>
+            <if test="is_subscribe != null">`is_subscribe` = #{is_subscribe}, </if>
+            <if test="trade_type != null">`trade_type` = #{trade_type}, </if>
+            <if test="fee_type != null">`fee_type` = #{fee_type}, </if>
+            <if test="total_fee != null">`total_fee` = #{total_fee}, </if>
+            <if test="transaction_id != null">`transaction_id` = #{transaction_id}, </if>
+            <if test="out_trade_no != null">`out_trade_no` = #{out_trade_no}, </if>
+            <if test="out_trade_no_wx != null">`out_trade_no_wx` = #{out_trade_no_wx}, </if>
+            <if test="attach != null">`attach` = #{attach}, </if>
+            <if test="time_end != null">`time_end` = #{time_end}, </if>
+            <if test="trade_state != null">`trade_state` = #{trade_state}, </if>
+            <if test="creater_sn != null">`creater_sn` = #{creater_sn}, </if>
+            <if test="create_time != null">`create_time` = #{create_time}, </if>
+            <if test="moder_sn != null">`moder_sn` = #{moder_sn}, </if>
+            <if test="mod_time != null">`mod_time` = #{mod_time}</if>
+        </set>
+        where id = #{id}
+    </update>
+
+    <select id="queryRecordList" resultType="map">
+        SELECT id,out_trade_no,out_trade_no_wx
+        FROM mall_order_wxpay_record
+        where trade_state in
+        <foreach collection="list" item="listItem" open="(" separator="," close=")">
+            #{listItem}
+        </foreach>
+    </select>
+
+    <select id="getRecordsByOutTradeNo" resultType="map">
+        SELECT id,trade_state,out_trade_no_wx
+        FROM mall_order_wxpay_record
+        where out_trade_no = #{out_trade_no}
+    </select>
+</mapper>

+ 7 - 0
kmall-schedule/src/main/resources/mybatis/mapper/QzOrderMapper.xml

@@ -149,4 +149,11 @@
         #{createTime},
         #{modTime})
     </update>
+
+
+    <select id="queryOrder" resultType="map">
+		select id,order_status
+        from mall_order
+        WHERE order_sn = #{orderSn}
+    </select>
 </mapper>