Explorar o código

支付模块,订单 接口业务移植

lyhzzz %!s(int64=3) %!d(string=hai) anos
pai
achega
553ba1da70
Modificáronse 65 ficheiros con 4340 adicións e 45 borrados
  1. 6 0
      4dkankan-center-platform/pom.xml
  2. 19 0
      4dkankan-center-platform/src/main/java/com/fdkankan/goods/common/SkuCache.java
  3. 1 1
      4dkankan-center-platform/src/main/java/com/fdkankan/goods/mapper/ICameraSpaceMapper.java
  4. 2 1
      4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/ICameraSpaceService.java
  5. 2 0
      4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/IGoodsService.java
  6. 10 0
      4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/IGoodsSkuService.java
  7. 4 4
      4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/impl/CameraDetailServiceImpl.java
  8. 2 2
      4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/impl/CameraServiceImpl.java
  9. 10 2
      4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/impl/CameraSpaceServiceImpl.java
  10. 13 0
      4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/impl/GoodsServiceImpl.java
  11. 46 1
      4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/impl/GoodsSkuServiceImpl.java
  12. 80 0
      4dkankan-center-platform/src/main/java/com/fdkankan/goods/vo/ResponseGoods.java
  13. 38 0
      4dkankan-center-platform/src/main/java/com/fdkankan/goods/vo/ResponseGoodsSku.java
  14. 25 0
      4dkankan-center-platform/src/main/java/com/fdkankan/order/constant/OrderEnum.java
  15. 9 0
      4dkankan-center-platform/src/main/java/com/fdkankan/order/mapper/IOrderItemMapper.java
  16. 5 0
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/ICommerceOrderService.java
  17. 5 0
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IDownloadOrderService.java
  18. 5 0
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IExpansionOrderService.java
  19. 5 0
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IIncrementOrderService.java
  20. 8 3
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IInvoiceService.java
  21. 4 0
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IOrderItemService.java
  22. 36 1
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IOrderService.java
  23. 3 0
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IVirtualOrderService.java
  24. 25 1
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/CommerceOrderServiceImpl.java
  25. 31 1
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/DownloadOrderServiceImpl.java
  26. 33 1
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/ExpansionOrderServiceImpl.java
  27. 30 1
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/IncrementOrderServiceImpl.java
  28. 242 16
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/InvoiceServiceImpl.java
  29. 11 0
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/OrderItemServiceImpl.java
  30. 454 2
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/OrderServiceImpl.java
  31. 28 0
      4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/VirtualOrderServiceImpl.java
  32. 58 0
      4dkankan-center-platform/src/main/java/com/fdkankan/order/vo/ResponseCommerceOrder.java
  33. 104 0
      4dkankan-center-platform/src/main/java/com/fdkankan/order/vo/ResponseExpansionOrder.java
  34. 11 7
      4dkankan-center-platform/src/main/java/com/fdkankan/user/controller/api/UserInvoiceController.java
  35. 175 0
      4dkankan-center-platform/src/main/java/com/fdkankan/user/controller/api/UserOrderController.java
  36. 33 0
      4dkankan-center-platform/src/main/java/com/fdkankan/user/request/RequestCommerceOrder.java
  37. 35 0
      4dkankan-center-platform/src/main/java/com/fdkankan/user/request/RequestExpansionOrder.java
  38. 44 0
      4dkankan-center-platform/src/main/java/com/fdkankan/user/request/RequestIncrementOrder.java
  39. 31 0
      4dkankan-center-platform/src/main/java/com/fdkankan/user/request/RequestOrder.java
  40. 27 0
      4dkankan-center-platform/src/main/java/com/fdkankan/user/request/RequestPlaceOrder.java
  41. 46 0
      4dkankan-center-platform/src/main/java/com/fdkankan/user/request/RequestVirtualOrder.java
  42. 41 0
      4dkankan-common/src/main/java/com/fdkankan/common/constant/Constant.java
  43. 17 0
      4dkankan-common/src/main/java/com/fdkankan/common/constant/OrderConstant.java
  44. 117 0
      4dkankan-pay/pom.xml
  45. 92 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/alipay/AlipayDefaultConfig.java
  46. 81 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/alipay/sdk/AlipayConfig.java
  47. 60 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/alipay/sdk/AlipayGoodsDetail.java
  48. 161 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/alipay/sdk/AlipayService.java
  49. 38 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/alipay/sdk/AlipayUtil.java
  50. 113 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/alipay/sdk/AlipaymentEx.java
  51. 56 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/PayPalDefaultConfig.java
  52. 43 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PayPalConfig.java
  53. 130 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PayPalmentEx.java
  54. 88 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PaypalOrderAddressEx.java
  55. 59 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PaypalOrderItemEx.java
  56. 5 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PaypalPaymentIntent.java
  57. 5 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PaypalPaymentMethod.java
  58. 268 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PaypalService.java
  59. 66 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/UrlUtils.java
  60. 64 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/wx/WXPayDefaultConfig.java
  61. 673 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/wx/sdk/WXPay.java
  62. 53 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/wx/sdk/WXPayConfig.java
  63. 45 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/wx/sdk/WXPayConstants.java
  64. 307 0
      4dkankan-pay/src/main/java/com/fdkankan/pay/wx/sdk/WXPayUtil.java
  65. 2 1
      pom.xml

+ 6 - 0
4dkankan-center-platform/pom.xml

@@ -21,6 +21,12 @@
       </dependency>
 
       <dependency>
+          <groupId>com.fdkankan</groupId>
+          <artifactId>4dkankan-pay</artifactId>
+          <version>2.0.0</version>
+      </dependency>
+
+      <dependency>
           <groupId>org.projectlombok</groupId>
           <artifactId>lombok</artifactId>
       </dependency>

+ 19 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/goods/common/SkuCache.java

@@ -0,0 +1,19 @@
+package com.fdkankan.goods.common;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SkuCache {
+
+    public static Map<String, String> skusMap = new HashMap<>();
+
+    static {
+        skusMap.put("1", "U15604126369780003,U15604126369840004,U15609161655710002,U15604132404280073");
+        skusMap.put("2", "U15604126369780013,U15604126369840014,U15609161655710012,U15604132404280083");
+        skusMap.put("3", "U15604126369780023,U15604126369840024,U15609161655710022,U15604132404280093");
+        skusMap.put("4", "U15604126369780033,U15604126369840034,U15609161655710032,U15604132404280103");
+        skusMap.put("5", "U15604132404280203");
+        skusMap.put("6", "U15604132404280303");
+    }
+
+}

+ 1 - 1
4dkankan-center-platform/src/main/java/com/fdkankan/goods/mapper/ICameraSpaceMapper.java

@@ -23,5 +23,5 @@ public interface ICameraSpaceMapper extends BaseMapper<CameraSpace> {
     @Select(" select s.id, s.space_end_time, c.child_name, s.space from t_camera_space s " +
             "LEFT JOIN t_camera c on s.camera_id = c.id where s.rec_status = 'A' and " +
             "s.space_type = 2 and s.camera_id = #{cameraId} and TIMESTAMPDIFF(MINUTE, NOW(), s.space_end_time) > -1 ORDER BY s.space_end_time ")
-    List<ResponseCameraSpace> getListByCameraId(@Param("cameraId")Long cameraId);
+    List<ResponseCameraSpace> getVoListByCameraId(@Param("cameraId")Long cameraId);
 }

+ 2 - 1
4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/ICameraSpaceService.java

@@ -16,5 +16,6 @@ import java.util.List;
  */
 public interface ICameraSpaceService extends IService<CameraSpace> {
 
-    List<ResponseCameraSpace> getListByCameraId(Long cameraId);
+    List<CameraSpace> getListByCameraId(Long cameraId);
+    List<ResponseCameraSpace> getVoListByCameraId(Long cameraId);
 }

+ 2 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/IGoodsService.java

@@ -2,6 +2,7 @@ package com.fdkankan.goods.service;
 
 import com.fdkankan.goods.entity.Goods;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.goods.vo.ResponseGoods;
 
 /**
  * <p>
@@ -13,4 +14,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface IGoodsService extends IService<Goods> {
 
+    ResponseGoods getByGoodsId(Long goodsId);
 }

+ 10 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/IGoodsSkuService.java

@@ -2,6 +2,10 @@ package com.fdkankan.goods.service;
 
 import com.fdkankan.goods.entity.GoodsSku;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.goods.vo.ResponseGoodsSku;
+import com.fdkankan.user.request.RequestCamera;
+
+import java.util.List;
 
 /**
  * <p>
@@ -13,4 +17,10 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface IGoodsSkuService extends IService<GoodsSku> {
 
+    ResponseGoodsSku getVoBySkuSn(String skuSn);
+    GoodsSku getBySkuSn(String skuSn);
+
+    List<GoodsSku> getByGoodsId(long goodsId);
+
+    ResponseGoodsSku getIncrementOrDownloadPrice(RequestCamera camera);
 }

+ 4 - 4
4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/impl/CameraDetailServiceImpl.java

@@ -212,7 +212,7 @@ public class CameraDetailServiceImpl extends ServiceImpl<ICameraDetailMapper, Ca
             }
         }
 
-        List<ResponseCameraSpace> cameraList = cameraSpaceService.getListByCameraId(vo.getId());
+        List<ResponseCameraSpace> cameraList = cameraSpaceService.getVoListByCameraId(vo.getId());
         if(cameraList != null && cameraList.size() > 0){
             ResponseCameraSpace cameraSpace = cameraList.get(0);
 
@@ -259,7 +259,7 @@ public class CameraDetailServiceImpl extends ServiceImpl<ICameraDetailMapper, Ca
             if (detailEntity == null){
                 throw new BusinessException(ErrorCode.CAMERA_BIND_NO_EXIST);
             }
-            List<ResponseCameraSpace> cameraList = cameraSpaceService.getListByCameraId(cameraEntity.getId());
+            List<ResponseCameraSpace> cameraList = cameraSpaceService.getVoListByCameraId(cameraEntity.getId());
 
             if(cameraList != null && cameraList.size() > 0){
                 ResponseCameraSpace cameraSpace = cameraList.get(0);
@@ -296,7 +296,7 @@ public class CameraDetailServiceImpl extends ServiceImpl<ICameraDetailMapper, Ca
         }
         List<ResponseCamera> cameras8 = cameraService.getByUser(userId, 4);
         for(ResponseCamera responseCamera : cameras8){
-            List<ResponseCameraSpace> cameraList = cameraSpaceService.getListByCameraId(responseCamera.getId());
+            List<ResponseCameraSpace> cameraList = cameraSpaceService.getVoListByCameraId(responseCamera.getId());
 
             if(cameraList != null && cameraList.size() > 0){
                 ResponseCameraSpace cameraSpace = cameraList.get(0);
@@ -346,7 +346,7 @@ public class CameraDetailServiceImpl extends ServiceImpl<ICameraDetailMapper, Ca
         Integer number = 0;
         List<ResponseCameraSpace> cameraList = null;
         for (CameraDetail cameraDetailEntity : list) {
-            cameraList = cameraSpaceService.getListByCameraId(cameraDetailEntity.getCameraId());
+            cameraList = cameraSpaceService.getVoListByCameraId(cameraDetailEntity.getCameraId());
             if(cameraList != null && cameraList.size() > 0){
                 if(Days.daysBetween(new DateTime(), new DateTime(cameraList.get(0).getSpaceEndTime())).getDays() < 30){
                     number++;

+ 2 - 2
4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/impl/CameraServiceImpl.java

@@ -120,7 +120,7 @@ public class CameraServiceImpl extends ServiceImpl<ICameraMapper, Camera> implem
         for (ResponseCamera responseCamera : list) {
             Integer surplusDate = null;
 
-            List<ResponseCameraSpace> cameraList = cameraSpaceService.getListByCameraId(responseCamera.getId());
+            List<ResponseCameraSpace> cameraList = cameraSpaceService.getVoListByCameraId(responseCamera.getId());
             if(cameraList != null && cameraList.size() > 0){
                 responseCamera.setSpace((long) FileSizeUtil.formetFileSize(cameraList.get(0).getSpace(), FileSizeUtil.SIZETYPE_GB));
                 responseCamera.setSpaceStr(FileSizeUtil.formatFileSize(cameraList.get(0).getSpace()));
@@ -263,7 +263,7 @@ public class CameraServiceImpl extends ServiceImpl<ICameraMapper, Camera> implem
             throw new BusinessException(AppConstant.FAILURE_CODE_4010, AppConstant.FAILURE_MSG_4010);
         }
 
-        return cameraSpaceService.getListByCameraId(cameraEntity.getId());
+        return cameraSpaceService.getVoListByCameraId(cameraEntity.getId());
     }
 
     @Override

+ 10 - 2
4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/impl/CameraSpaceServiceImpl.java

@@ -1,5 +1,6 @@
 package com.fdkankan.goods.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fdkankan.goods.entity.CameraSpace;
 import com.fdkankan.goods.mapper.ICameraSpaceMapper;
@@ -25,7 +26,14 @@ public class CameraSpaceServiceImpl extends ServiceImpl<ICameraSpaceMapper, Came
     private ICameraSpaceMapper cameraSpaceMapper;
 
     @Override
-    public List<ResponseCameraSpace> getListByCameraId(Long cameraId) {
-        return cameraSpaceMapper.getListByCameraId(cameraId);
+    public List<CameraSpace> getListByCameraId(Long cameraId) {
+        QueryWrapper<CameraSpace> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(CameraSpace::getCameraId,cameraId);
+        return this.list(queryWrapper);
+    }
+
+    @Override
+    public List<ResponseCameraSpace> getVoListByCameraId(Long cameraId) {
+        return cameraSpaceMapper.getVoListByCameraId(cameraId);
     }
 }

+ 13 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/impl/GoodsServiceImpl.java

@@ -4,6 +4,8 @@ import com.fdkankan.goods.entity.Goods;
 import com.fdkankan.goods.mapper.IGoodsMapper;
 import com.fdkankan.goods.service.IGoodsService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.goods.vo.ResponseGoods;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 
 /**
@@ -17,4 +19,15 @@ import org.springframework.stereotype.Service;
 @Service
 public class GoodsServiceImpl extends ServiceImpl<IGoodsMapper, Goods> implements IGoodsService {
 
+    @Override
+    public ResponseGoods getByGoodsId(Long goodsId) {
+        Goods goods = this.getById(goodsId);
+        ResponseGoods responseGoods = null;
+        if (goods != null){
+            responseGoods = new ResponseGoods();
+            BeanUtils.copyProperties(goods, responseGoods);
+            responseGoods.setGoodsStatus(goods.getGoodsStatus());
+        }
+        return responseGoods;
+    }
 }

+ 46 - 1
4dkankan-center-platform/src/main/java/com/fdkankan/goods/service/impl/GoodsSkuServiceImpl.java

@@ -1,11 +1,19 @@
 package com.fdkankan.goods.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.goods.common.SkuCache;
 import com.fdkankan.goods.entity.GoodsSku;
 import com.fdkankan.goods.mapper.IGoodsSkuMapper;
 import com.fdkankan.goods.service.IGoodsSkuService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.goods.vo.ResponseGoodsSku;
+import com.fdkankan.user.request.RequestCamera;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
+
 /**
  * <p>
  * 商品sku表 服务实现类
@@ -17,4 +25,41 @@ import org.springframework.stereotype.Service;
 @Service
 public class GoodsSkuServiceImpl extends ServiceImpl<IGoodsSkuMapper, GoodsSku> implements IGoodsSkuService {
 
+    @Override
+    public ResponseGoodsSku getVoBySkuSn(String skuSn) {
+        ResponseGoodsSku responseGoodsSku = null;
+        GoodsSku bySkuSn = this.getBySkuSn(skuSn);
+        if(bySkuSn!=null){
+            BeanUtils.copyProperties(bySkuSn,responseGoodsSku);
+        }
+        return responseGoodsSku;
+    }
+
+    @Override
+    public GoodsSku getBySkuSn(String skuSn) {
+        QueryWrapper<GoodsSku> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(GoodsSku::getSkuSn,skuSn);
+        queryWrapper.last("LIMIT 1");
+        List<GoodsSku> list = this.list(queryWrapper);
+        if(list == null || list.size()<=0){
+            return null;
+        }
+        return list.get(0);
+    }
+
+    @Override
+    public List<GoodsSku> getByGoodsId(long goodsId) {
+        QueryWrapper<GoodsSku> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(GoodsSku::getGoodsId,goodsId);
+        return this.list(queryWrapper);
+    }
+
+    @Override
+    public ResponseGoodsSku getIncrementOrDownloadPrice(RequestCamera camera) {
+        String skuStr = SkuCache.skusMap.get(String.valueOf(camera.getDateType()));
+        if (StringUtils.isEmpty(skuStr)){
+            skuStr = SkuCache.skusMap.get("5");
+        }
+        return this.getVoBySkuSn(skuStr);
+    }
 }

+ 80 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/goods/vo/ResponseGoods.java

@@ -0,0 +1,80 @@
+package com.fdkankan.goods.vo;
+
+import com.fdkankan.common.request.RequestBase;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class ResponseGoods extends RequestBase implements Serializable {
+
+    private static final long serialVersionUID = 1488438481056104795L;
+    private Long id;
+    /**
+     * 商品名称
+     */
+   //(value = "商品名称", name = "name")
+    private String name;
+    /**
+     * 套餐
+     */
+   //(value = "套餐", name = "packageName")
+    private String packageName;
+    /**
+     * 商品详情
+     */
+   //(value = "商品详情", name = "description")
+    private String description;
+    /**
+     * 商品图片
+     */
+   //(value = "商品图片", name = "imageUrl")
+    private String imageUrl;
+    /**
+     * 商品图片2
+     */
+   //(value = "商品图片2", name = "pic")
+    private String pic;
+    /**
+     * 商品价格(RMB)
+     */
+   //(value = "商品价格(RMB)", name = "goodsPrice")
+    private BigDecimal goodsPrice;
+    /**
+     * 商品价格(美元)
+     */
+   //(value = "商品价格(美元)", name = "goodsDollarPrice")
+    private BigDecimal goodsDollarPrice;
+    /**
+     * 快递价格
+     */
+   //(value = "快递价格", name = "expressPrice")
+    private BigDecimal expressPrice;
+    /**
+     * 商品编码
+     */
+   //(value = "商品编码", name = "goodsSn")
+    private String goodsSn;
+    /**
+     * 商品状态,上架下架
+     */
+   //(value = "商品状态,上架下架", name = "goodsStatus")
+    private String goodsStatus;
+    /**
+     * 排序
+     */
+    private int sort;
+    /**
+     * 规格描述
+     */
+    private String attributeList;
+    /**
+     * skus
+     */
+    private List<ResponseGoodsSku> skuList;
+
+    private Long deadLine;
+
+}

+ 38 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/goods/vo/ResponseGoodsSku.java

@@ -0,0 +1,38 @@
+package com.fdkankan.goods.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class ResponseGoodsSku implements Serializable {
+
+    private static final long serialVersionUID = -873854526108879341L;
+
+    private Long id;
+
+    private Long goodsId;
+
+    private String skuSn;
+
+    private String description;
+
+    private int stock;
+
+    private BigDecimal price;
+
+    private BigDecimal costPrice;
+
+    private BigDecimal dollarPrice;
+
+    private BigDecimal costDollarPrice;
+    //扩容专用
+    private String unit;
+    //扩容大小
+    private int unitSize;
+    //扩容期限,单位月
+    private int month;
+    //预计到期时间
+    private Long deadLine;
+}

+ 25 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/order/constant/OrderEnum.java

@@ -0,0 +1,25 @@
+package com.fdkankan.order.constant;
+
+import lombok.Data;
+
+@Data
+public class OrderEnum {
+    /**
+     * 订单状态(未处理、已确认、已完成、已取消)
+     */
+    public enum OrderStatus {
+        unprocessed, processed, completed, invalid, expire
+    };
+    /**
+     * 付款状态(未付款、已付款、已取消, 部分支付, 部分退款, 全额退款)
+     */
+    public enum PaymentStatus {
+        unpaid, paid, cancel, partPayment, partRefund, refunded
+    };
+    /**
+     * 配送状态(未发货、部分发货、已发货、部分退货、已退货、已收货)
+     */
+    public enum ShippingStatus {
+        unshipped, partShipped, shipped, partReshiped, reshiped, received
+    };
+}

+ 9 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/order/mapper/IOrderItemMapper.java

@@ -2,7 +2,12 @@ package com.fdkankan.order.mapper;
 
 import com.fdkankan.order.entity.OrderItem;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fdkankan.user.vo.ResponseOrderItem;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
 
 /**
  * <p>
@@ -15,4 +20,8 @@ import org.apache.ibatis.annotations.Mapper;
 @Mapper
 public interface IOrderItemMapper extends BaseMapper<OrderItem> {
 
+    @Select(" SELECT i.id, i.goods_name, i.goods_count, i.goods_price, g.description, g.pic, i.sku_sn, i.express_name, i.express_num, i.shipping_status, i.order_id, i.goods_id FROM" +
+            " t_order_item i LEFT JOIN t_order o ON o.id = i.order_id " +
+            "LEFT JOIN t_goods g ON i.goods_id = g.id where i.rec_status = 'A' and o.id = #{orderId} ")
+    List<ResponseOrderItem> getByOrderId(@Param("orderId") Long orderId);
 }

+ 5 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/ICommerceOrderService.java

@@ -2,6 +2,10 @@ package com.fdkankan.order.service;
 
 import com.fdkankan.order.entity.CommerceOrder;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.order.vo.ResponseCommerceOrder;
+import com.fdkankan.user.request.RequestCommerceOrder;
+
+import java.math.BigDecimal;
 
 /**
  * <p>
@@ -13,4 +17,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface ICommerceOrderService extends IService<CommerceOrder> {
 
+    ResponseCommerceOrder saveByOrderParam(Long userId, RequestCommerceOrder param, BigDecimal bigDecimal);
 }

+ 5 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IDownloadOrderService.java

@@ -2,6 +2,10 @@ package com.fdkankan.order.service;
 
 import com.fdkankan.order.entity.DownloadOrder;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.user.request.RequestIncrementOrder;
+import com.fdkankan.user.vo.ResponseDownloadOrder;
+
+import java.math.BigDecimal;
 
 /**
  * <p>
@@ -13,4 +17,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface IDownloadOrderService extends IService<DownloadOrder> {
 
+    ResponseDownloadOrder saveByOrderParam(Long userId, RequestIncrementOrder order, BigDecimal price);
 }

+ 5 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IExpansionOrderService.java

@@ -2,6 +2,10 @@ package com.fdkankan.order.service;
 
 import com.fdkankan.order.entity.ExpansionOrder;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.order.vo.ResponseExpansionOrder;
+import com.fdkankan.user.request.RequestExpansionOrder;
+
+import java.math.BigDecimal;
 
 /**
  * <p>
@@ -13,4 +17,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface IExpansionOrderService extends IService<ExpansionOrder> {
 
+    ResponseExpansionOrder saveByOrderParam(Long userId, RequestExpansionOrder order, BigDecimal bigDecimal, String unit, int unitSize, int month, int delay);
 }

+ 5 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IIncrementOrderService.java

@@ -2,6 +2,10 @@ package com.fdkankan.order.service;
 
 import com.fdkankan.order.entity.IncrementOrder;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.user.request.RequestIncrementOrder;
+import com.fdkankan.user.vo.ResponseIncrementOrder;
+
+import java.math.BigDecimal;
 
 /**
  * <p>
@@ -13,4 +17,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface IIncrementOrderService extends IService<IncrementOrder> {
 
+    ResponseIncrementOrder saveByOrderParam(Long userId, RequestIncrementOrder order, BigDecimal price);
 }

+ 8 - 3
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IInvoiceService.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.fdkankan.order.entity.Invoice;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fdkankan.user.request.RequestInvoice;
+import com.fdkankan.user.request.RequestPlaceOrder;
 import com.fdkankan.user.vo.ResponseInvoice;
 
 /**
@@ -20,11 +21,11 @@ public interface IInvoiceService extends IService<Invoice> {
 
     Page<ResponseInvoice> listInvoice(RequestInvoice param, String token);
 
-    String mineInvoice(RequestInvoice param, String token);
+    ResponseInvoice mineInvoice(RequestInvoice param, String token);
 
     String saveInvoice(RequestInvoice param, String token);
 
-    String detailInvoice(RequestInvoice param, String token);
+    ResponseInvoice detailInvoice(RequestInvoice param, String token);
 
     String addInvoice(RequestInvoice param, String token);
 
@@ -32,5 +33,9 @@ public interface IInvoiceService extends IService<Invoice> {
 
     String deleteInvoice(RequestInvoice param, String token);
 
-    String openInvoice(RequestInvoice param, String token);
+    ResponseInvoice openInvoice(RequestInvoice param, String token);
+
+    Invoice getByOrderId(Long orderId);
+
+    void saveInvoiceByOrder(Long userId, RequestPlaceOrder order);
 }

+ 4 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IOrderItemService.java

@@ -2,6 +2,9 @@ package com.fdkankan.order.service;
 
 import com.fdkankan.order.entity.OrderItem;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.user.vo.ResponseOrderItem;
+
+import java.util.List;
 
 /**
  * <p>
@@ -13,4 +16,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface IOrderItemService extends IService<OrderItem> {
 
+    List<ResponseOrderItem> getByOrderId(Long orderId);
 }

+ 36 - 1
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IOrderService.java

@@ -1,7 +1,14 @@
 package com.fdkankan.order.service;
 
-import com.fdkankan.order.entity.Order;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.goods.vo.ResponseGoods;
+import com.fdkankan.goods.vo.ResponseGoodsSku;
+import com.fdkankan.order.entity.Order;
+import com.fdkankan.order.vo.ResponseCommerceOrder;
+import com.fdkankan.order.vo.ResponseExpansionOrder;
+import com.fdkankan.user.request.*;
+import com.fdkankan.user.vo.*;
 
 /**
  * <p>
@@ -13,4 +20,32 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface IOrderService extends IService<Order> {
 
+    ResponseOrder getOrderDetail(Long orderId);
+
+    Page<ResponseOrder> getOrders(RequestOrder param, String token);
+
+    String cancelOrder(RequestOrder param, String token);
+
+    String receiptOrder(RequestOrder param, String token);
+
+    ResponseInvoice getInvoiceDetail(RequestOrder param, String token);
+
+    ResponseOrder placeOrder(RequestPlaceOrder param, String token);
+
+    ResponseVirtualOrder rechargeOrder(RequestCamera param, String token);
+
+    ResponseExpansionOrder expansionOrder(RequestExpansionOrder param, String token);
+
+    ResponseCommerceOrder commerceOrder(RequestCommerceOrder param, String token);
+
+    ResponseIncrementOrder incrementOrder(RequestIncrementOrder param, String token);
+
+    ResponseDownloadOrder downloadOrder(RequestIncrementOrder param, String token);
+
+    Boolean queryOrderStatus(RequestVirtualOrder param, String token) throws Exception;
+
+    ResponseGoods getExpansionPrice(RequestCamera param, String token);
+
+    ResponseGoodsSku getIncrementOrDownloadPrice(RequestCamera param, String token);
+
 }

+ 3 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/IVirtualOrderService.java

@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.fdkankan.agent.vo.AgentVo;
 import com.fdkankan.agent.vo.ResponseAgentCamera;
 import com.fdkankan.order.entity.VirtualOrder;
+import com.fdkankan.user.request.RequestCamera;
+import com.fdkankan.user.vo.ResponseVirtualOrder;
 
 /**
  * <p>
@@ -21,4 +23,5 @@ public interface IVirtualOrderService extends IService<VirtualOrder> {
 
     ResponseAgentCamera getPointsByCameraId(Long cameraId, String startDate, String endDate);
 
+    ResponseVirtualOrder saveByCamera(Long id, RequestCamera param);
 }

+ 25 - 1
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/CommerceOrderServiceImpl.java

@@ -1,11 +1,17 @@
 package com.fdkankan.order.service.impl;
 
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.common.util.NumberUtils;
 import com.fdkankan.order.entity.CommerceOrder;
 import com.fdkankan.order.mapper.ICommerceOrderMapper;
 import com.fdkankan.order.service.ICommerceOrderService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.order.vo.ResponseCommerceOrder;
+import com.fdkankan.user.request.RequestCommerceOrder;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
+
 /**
  * <p>
  * 商业订单表(八目相机) 服务实现类
@@ -17,4 +23,22 @@ import org.springframework.stereotype.Service;
 @Service
 public class CommerceOrderServiceImpl extends ServiceImpl<ICommerceOrderMapper, CommerceOrder> implements ICommerceOrderService {
 
+    @Override
+    public ResponseCommerceOrder saveByOrderParam(Long userId, RequestCommerceOrder order, BigDecimal price) {
+        BigDecimal total = price.multiply(new BigDecimal(order.getCount()));
+        CommerceOrder commerceOrderEntity = new CommerceOrder();
+        commerceOrderEntity.setOrderSn(NumberUtils.getOrderSn());
+        commerceOrderEntity.setAmount(total);
+        commerceOrderEntity.setPayType(order.getPayType());
+        commerceOrderEntity.setPayStatus(-1);
+        commerceOrderEntity.setUserId(userId);
+        commerceOrderEntity.setCommerceType(order.getCommerceType());
+        commerceOrderEntity.setCount(order.getCount());
+        commerceOrderEntity.setCameraId(order.getCameraId());
+        commerceOrderEntity.setAbroad(order.getAbroad());
+        this.save(commerceOrderEntity);
+        ResponseCommerceOrder commerceOrder = new ResponseCommerceOrder();
+        BeanUtils.copyProperties(commerceOrderEntity, commerceOrder);
+        return commerceOrder;
+    }
 }

+ 31 - 1
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/DownloadOrderServiceImpl.java

@@ -1,11 +1,19 @@
 package com.fdkankan.order.service.impl;
 
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.common.util.NumberUtils;
 import com.fdkankan.order.entity.DownloadOrder;
 import com.fdkankan.order.mapper.IDownloadOrderMapper;
 import com.fdkankan.order.service.IDownloadOrderService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.user.request.RequestIncrementOrder;
+import com.fdkankan.user.vo.ResponseDownloadOrder;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
+
 /**
  * <p>
  * 下载次数订单表 服务实现类
@@ -17,4 +25,26 @@ import org.springframework.stereotype.Service;
 @Service
 public class DownloadOrderServiceImpl extends ServiceImpl<IDownloadOrderMapper, DownloadOrder> implements IDownloadOrderService {
 
+    @Override
+    public ResponseDownloadOrder saveByOrderParam(Long userId, RequestIncrementOrder order, BigDecimal price) {
+        BigDecimal total = price.multiply(new BigDecimal(order.getCount()));
+
+        DownloadOrder downloadOrderEntity = new DownloadOrder();
+        downloadOrderEntity.setOrderSn(NumberUtils.getOrderSn());
+        downloadOrderEntity.setAmount(total);
+        downloadOrderEntity.setPayType(order.getPayType());
+        downloadOrderEntity.setPayStatus(-1);
+        downloadOrderEntity.setUserId(userId);
+        downloadOrderEntity.setCount(order.getCount());
+        downloadOrderEntity.setAbroad(order.getAbroad());
+        downloadOrderEntity.setDownStatus(1);
+        downloadOrderEntity.setSceneNum(order.getSceneNum());
+        downloadOrderEntity.setSceneName(order.getSceneName());
+        if(!this.save(downloadOrderEntity)){
+            throw new BusinessException(ErrorCode.ERROR_MSG);
+        }
+        ResponseDownloadOrder downloadOrder = new ResponseDownloadOrder();
+        BeanUtils.copyProperties(downloadOrderEntity, downloadOrder);
+        return downloadOrder;
+    }
 }

+ 33 - 1
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/ExpansionOrderServiceImpl.java

@@ -1,11 +1,19 @@
 package com.fdkankan.order.service.impl;
 
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.common.util.NumberUtils;
 import com.fdkankan.order.entity.ExpansionOrder;
 import com.fdkankan.order.mapper.IExpansionOrderMapper;
 import com.fdkankan.order.service.IExpansionOrderService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.order.vo.ResponseExpansionOrder;
+import com.fdkankan.user.request.RequestExpansionOrder;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
+
 /**
  * <p>
  * 扩容订单表(八目相机) 服务实现类
@@ -17,4 +25,28 @@ import org.springframework.stereotype.Service;
 @Service
 public class ExpansionOrderServiceImpl extends ServiceImpl<IExpansionOrderMapper, ExpansionOrder> implements IExpansionOrderService {
 
+    @Override
+    public ResponseExpansionOrder saveByOrderParam(Long userId, RequestExpansionOrder order, BigDecimal price, String unit, int unitSize, int month, int delay) {
+        BigDecimal total = price.multiply(new BigDecimal(order.getUnitSize())).multiply(new BigDecimal(order.getYears()));
+        ExpansionOrder expansionOrderEntity = new ExpansionOrder();
+        expansionOrderEntity.setOrderSn(NumberUtils.getOrderSn());
+        expansionOrderEntity.setAmount(total);
+        expansionOrderEntity.setPayType(order.getPayType());
+        expansionOrderEntity.setPayStatus(-1);
+        expansionOrderEntity.setStatus(-1);
+        expansionOrderEntity.setUserId(userId);
+        expansionOrderEntity.setCameraId(order.getCameraId());
+        expansionOrderEntity.setYears(0);
+        expansionOrderEntity.setMonth(month);
+        expansionOrderEntity.setDelay(delay);
+        expansionOrderEntity.setUnitSize(unitSize);
+        expansionOrderEntity.setUnit(unit);
+        expansionOrderEntity.setAbroad(order.getAbroad());
+        if(!this.save(expansionOrderEntity)){
+            throw new BusinessException(ErrorCode.ERROR_MSG);
+        }
+        ResponseExpansionOrder expansionOrder = new ResponseExpansionOrder();
+        BeanUtils.copyProperties(expansionOrderEntity, expansionOrder);
+        return expansionOrder;
+    }
 }

+ 30 - 1
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/IncrementOrderServiceImpl.java

@@ -1,11 +1,19 @@
 package com.fdkankan.order.service.impl;
 
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.common.util.NumberUtils;
 import com.fdkankan.order.entity.IncrementOrder;
 import com.fdkankan.order.mapper.IIncrementOrderMapper;
 import com.fdkankan.order.service.IIncrementOrderService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.user.request.RequestIncrementOrder;
+import com.fdkankan.user.vo.ResponseIncrementOrder;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
+
 /**
  * <p>
  * 增值权益订单表 服务实现类
@@ -17,4 +25,25 @@ import org.springframework.stereotype.Service;
 @Service
 public class IncrementOrderServiceImpl extends ServiceImpl<IIncrementOrderMapper, IncrementOrder> implements IIncrementOrderService {
 
+    @Override
+    public ResponseIncrementOrder saveByOrderParam(Long userId, RequestIncrementOrder order, BigDecimal price) {
+        BigDecimal total = price.multiply(new BigDecimal(order.getCount()));
+
+        IncrementOrder incrementOrderEntity = new IncrementOrder();
+        incrementOrderEntity.setOrderSn(NumberUtils.getOrderSn());
+        incrementOrderEntity.setAmount(total);
+        incrementOrderEntity.setPayType(order.getPayType());
+        incrementOrderEntity.setPayStatus(-1);
+        incrementOrderEntity.setUserId(userId);
+        incrementOrderEntity.setCount(order.getCount());
+        incrementOrderEntity.setAbroad(order.getAbroad());
+        incrementOrderEntity.setStatus(order.getIncrementId() == null ? 1 : 2);
+        incrementOrderEntity.setIncrementId(order.getIncrementId());
+        if(!this.save(incrementOrderEntity)){
+            throw  new BusinessException(ErrorCode.ERROR_MSG);
+        }
+        ResponseIncrementOrder incrementOrder = new ResponseIncrementOrder();
+        BeanUtils.copyProperties(incrementOrderEntity, incrementOrder);
+        return incrementOrder;
+    }
 }

+ 242 - 16
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/InvoiceServiceImpl.java

@@ -3,21 +3,25 @@ package com.fdkankan.order.service.impl;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.fdkankan.order.entity.ExpansionOrder;
-import com.fdkankan.order.entity.Invoice;
-import com.fdkankan.order.entity.VirtualOrder;
+import com.fdkankan.common.constant.AppConstant;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.constant.OrderConstant;
+import com.fdkankan.common.constant.ServerCode;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.order.entity.*;
 import com.fdkankan.order.mapper.IInvoiceMapper;
-import com.fdkankan.order.service.IExpansionOrderService;
-import com.fdkankan.order.service.IInvoiceService;
-import com.fdkankan.order.service.IVirtualOrderService;
+import com.fdkankan.order.service.*;
 import com.fdkankan.user.entity.SSOUser;
 import com.fdkankan.user.request.RequestInvoice;
+import com.fdkankan.user.request.RequestPlaceOrder;
 import com.fdkankan.user.service.IUserService;
 import com.fdkankan.user.vo.ResponseInvoice;
+import com.fdkankan.user.vo.ResponseOrder;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -38,6 +42,10 @@ public class InvoiceServiceImpl extends ServiceImpl<IInvoiceMapper, Invoice> imp
     private IExpansionOrderService expansionOrderService;
     @Autowired
     private IUserService userService;
+    @Autowired
+    private IOrderService orderService;
+    @Autowired
+    private IIncrementOrderService incrementOrderService;
 
     @Override
     public Integer getMaxInvoice(RequestInvoice param, String token) {
@@ -118,37 +126,255 @@ public class InvoiceServiceImpl extends ServiceImpl<IInvoiceMapper, Invoice> imp
     }
 
     @Override
-    public String mineInvoice(RequestInvoice param, String token) {
-        return null;
+    public ResponseInvoice mineInvoice(RequestInvoice param, String token) {
+        SSOUser ssoUser = userService.getSSOUserByToken(token);
+        Invoice mineInvoice = getMineInvoice(ssoUser.getId(), param.getInvoiceType());
+        ResponseInvoice responseInvoice = new ResponseInvoice();
+        BeanUtils.copyProperties(mineInvoice,responseInvoice);
+        return responseInvoice;
+    }
+    private Invoice getMineInvoice(Long userId,String invoiceType){
+        QueryWrapper<Invoice> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(Invoice::getUserId,userId);
+        queryWrapper.lambda().eq(Invoice::getConsumeType ,-1);
+        queryWrapper.lambda().eq(Invoice::getType ,invoiceType);
+        queryWrapper.lambda().last("LIMIT 1");
+        List<Invoice> list = this.list(queryWrapper);
+        if(list == null || list.size()<=0){
+            return null;
+        }
+        return list.get(0);
     }
 
     @Override
     public String saveInvoice(RequestInvoice param, String token) {
-        return null;
+        SSOUser ssoUser = userService.getSSOUserByToken(token);
+        Invoice dbEntity = getMineInvoice(ssoUser.getId(), param.getInvoiceType());
+        if (dbEntity == null){
+            dbEntity = new Invoice();
+        }
+        if (param.getCameraId() != null){
+            dbEntity.setCameraId(param.getCameraId());
+        }
+        dbEntity.setType(Integer.valueOf(param.getInvoiceType()));
+        dbEntity.setUserId(ssoUser.getId());
+        dbEntity.setBankAccount(param.getBankAccount());
+        dbEntity.setBankName(param.getBankName());
+        dbEntity.setRegisterPhone(param.getRegisterPhone());
+        dbEntity.setOrganizedAddress(param.getOrganizedAddress());
+        dbEntity.setCode(param.getCode());
+        dbEntity.setTitle(param.getTitle());
+        dbEntity.setEmailAddress(param.getEmailAddress());
+        dbEntity.setConsumeType(-1);
+        if(!this.saveOrUpdate(dbEntity)){
+            throw new BusinessException(ErrorCode.ERROR_MSG);
+        }
+        return ServerCode.SUCCESS.message();
     }
 
     @Override
-    public String detailInvoice(RequestInvoice param, String token) {
-        return null;
+    public ResponseInvoice detailInvoice(RequestInvoice param, String token) {
+        Invoice invoice = this.getById(param.getInvoiceId());
+        ResponseInvoice responseInvoice = new ResponseInvoice();
+        if(invoice == null){
+            return responseInvoice;
+        }
+        BeanUtils.copyProperties(invoice, responseInvoice);
+        return responseInvoice;
     }
 
     @Override
     public String addInvoice(RequestInvoice param, String token) {
-        return null;
+        SSOUser ssoUser = userService.getSSOUserByToken(token);
+        if(param.getAmount() == null){
+            throw new BusinessException(ErrorCode.MISSING_REQUIRED_PARAMETERS);
+        }
+        int maxInvoice = this.getMaxInvoice(param.getCameraId());
+
+        if(Integer.parseInt(param.getAmount()) > maxInvoice){
+            throw new BusinessException(OrderConstant.FAILURE_CODE_8003, OrderConstant.FAILURE_MSG_8003);
+        }
+        return saveOrUpdateInvoice(ssoUser.getId(),param,null);
+    }
+    private String saveOrUpdateInvoice(Long userId,RequestInvoice param,Invoice invoiceEntity){
+        if(invoiceEntity == null){
+             invoiceEntity = new Invoice();
+            invoiceEntity.setUserId(userId);
+            invoiceEntity.setOrderId(param.getOrderId());
+        }
+        invoiceEntity.setType(Integer.valueOf(param.getInvoiceType()));
+        invoiceEntity.setTitle(param.getTitle());
+        invoiceEntity.setCode(param.getCode());
+
+        if (3 == invoiceEntity.getType()){
+            invoiceEntity.setOrganizedAddress(param.getOrganizedAddress());
+            invoiceEntity.setRegisterPhone(param.getRegisterPhone());
+            invoiceEntity.setBankName(param.getBankName());
+            invoiceEntity.setBankAccount(param.getBankAccount());
+        }
+
+        invoiceEntity.setCameraId(param.getCameraId());
+        invoiceEntity.setMoney(new BigDecimal(param.getAmount()));
+        invoiceEntity.setConsumeType(param.getConsumeType() == null? 1 : param.getConsumeType());
+
+        invoiceEntity.setShipName(param.getShipName());
+        invoiceEntity.setShipMobile(param.getShipMobile());
+        invoiceEntity.setShipAddress(param.getShipAddress());
+        invoiceEntity.setShipAreaPath(param.getShipAreaPath());
+        invoiceEntity.setCameraId(param.getCameraId());
+        invoiceEntity.setEmailAddress(param.getEmailAddress());
+        if(!this.saveOrUpdate(invoiceEntity)){
+            throw new BusinessException(ErrorCode.ERROR_MSG);
+        }
+        return ServerCode.SUCCESS.message();
     }
 
     @Override
     public String updateInvoice(RequestInvoice param, String token) {
-        return null;
+        SSOUser ssoUser = userService.getSSOUserByToken(token);
+
+        if(param.getInvoiceId() != null){
+            Invoice invoiceEntity = this.getById(param.getInvoiceId());
+            if(invoiceEntity == null){
+                throw new BusinessException(ErrorCode.NOT_RECORD);
+            }
+            return this.saveOrUpdateInvoice(ssoUser.getId(), param,invoiceEntity);
+        }
+        ResponseOrder order = orderService.getOrderDetail(param.getOrderId());
+        if(order == null || order.getTotalAmount() == null){
+            throw new BusinessException(ErrorCode.ERROR_MSG);
+        }
+        param.setAmount(order.getTotalAmount().toString());
+        return  this.saveOrUpdateInvoice(ssoUser.getId(),param,null);
     }
 
+
     @Override
     public String deleteInvoice(RequestInvoice param, String token) {
-        return null;
+        if(param == null || param.getInvoiceId() == null){
+            throw new BusinessException(ErrorCode.MISSING_REQUIRED_PARAMETERS);
+        }
+        if(!this.removeById(param.getInvoiceId())){
+            throw new BusinessException(ErrorCode.ERROR_MSG);
+        }
+        return ServerCode.SUCCESS.message();
     }
 
     @Override
-    public String openInvoice(RequestInvoice param, String token) {
-        return null;
+    public ResponseInvoice openInvoice(RequestInvoice param, String token) {
+        SSOUser ssoUser = userService.getSSOUserByToken(token);
+
+        //验证是否已经开票
+        this.checkInvoice(param.getOrderId(),param.getConsumeType());
+        //获取开票金额
+        BigDecimal money = this.getMoney(param.getOrderId(),param.getConsumeType());
+
+        Invoice dbEntity = new Invoice();
+        BeanUtils.copyProperties(param, dbEntity);
+
+        dbEntity.setOrderId(null);
+        switch (param.getConsumeType()){
+            case 0: dbEntity.setOrderId(param.getOrderId());break;
+            case 1: dbEntity.setVirtualOrderId(param.getOrderId());break;
+            case 2: dbEntity.setIncrementOrderId(param.getOrderId());break;
+            case 3: dbEntity.setDownloadOrderId(param.getOrderId());break;
+        }
+
+        if (param.getCameraId() != null){
+            dbEntity.setCameraId(param.getCameraId());
+        }
+//        dbEntity.setType(Integer.valueOf(param.get));
+        dbEntity.setUserId(ssoUser.getId());
+        dbEntity.setMoney(money);
+        this.save(dbEntity);
+
+        ResponseInvoice responseInvoice = new ResponseInvoice();
+        BeanUtils.copyProperties(dbEntity,responseInvoice);
+        return responseInvoice;
+    }
+
+    private BigDecimal getMoney(Long orderId, Integer consumeType) {
+        BigDecimal money = null;
+        switch (consumeType){
+            case 1 :
+                VirtualOrder virtualOrder = virtualOrderService.getById(orderId);
+                if(virtualOrder!=null && virtualOrder.getPayStatus() ==1){
+                    money = virtualOrder.getAmount();
+                }
+                break;
+            case 2 :
+                IncrementOrder incrementOrder = incrementOrderService.getById(orderId);
+                if(incrementOrder!=null && incrementOrder.getPayStatus() ==1){
+                    money = incrementOrder.getAmount();
+                }
+                break;
+            default:
+                Order order = orderService.getById(orderId);
+                if(order!=null && "paid".equals(order.getPaymentStatus())){
+                    money = order.getTotalAmount();
+                }
+                break;
+        }
+        return money;
+    }
+
+    private void checkInvoice(Long orderId, Integer consumeType) {
+        QueryWrapper<Invoice> queryWrapper = new QueryWrapper<>();
+        switch (consumeType){
+            case 1 :    //验证 消费订单是否开票
+                queryWrapper.lambda().eq(Invoice::getVirtualOrderId,orderId);break;
+            case 2 :    //验证 权益订单是否开票
+                queryWrapper.lambda().eq(Invoice::getIncrementOrderId,orderId);
+            case 3 :    //验证 下载订单是否开票
+                queryWrapper.lambda().eq(Invoice::getDownloadOrderId,orderId);break;
+            default:
+                queryWrapper.lambda().eq(Invoice::getOrderId,orderId);break;
+        }
+        List<Invoice> list = this.list(queryWrapper);
+        if(list==null || list.size()<=0){
+            throw new BusinessException(AppConstant.FAILURE_CODE_4021,AppConstant.FAILURE_MSG_4021);
+        }
+    }
+
+
+    @Override
+    public Invoice getByOrderId(Long orderId) {
+        QueryWrapper<Invoice> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(Invoice::getOrderId,orderId);
+        queryWrapper.last("LIMIT 1");
+        List<Invoice> list = this.list(queryWrapper);
+        if(list==null || list.size()<=0){
+            return null;
+        }
+        return list.get(0);
+    }
+
+    @Override
+    public void saveInvoiceByOrder(Long userId, RequestPlaceOrder order) {
+        RequestInvoice param = order.getInvoice();
+        Invoice invoiceEntity = new Invoice();
+        invoiceEntity.setUserId(userId);
+        invoiceEntity.setType(Integer.valueOf(param.getInvoiceType()));
+        invoiceEntity.setTitle(param.getTitle());
+        invoiceEntity.setCode(param.getCode());
+        invoiceEntity.setEmailAddress(param.getEmailAddress());
+        if (3 == invoiceEntity.getType()){
+            invoiceEntity.setOrganizedAddress(param.getOrganizedAddress());
+            invoiceEntity.setRegisterPhone(param.getRegisterPhone());
+            invoiceEntity.setBankName(param.getBankName());
+            invoiceEntity.setBankAccount(param.getBankAccount());
+        }
+        invoiceEntity.setConsumeType(0);
+        invoiceEntity.setOrderId(order.getOrderId());
+        invoiceEntity.setShipName(order.getReceiver().getShipName());
+        invoiceEntity.setShipMobile(order.getReceiver().getShipMobile());
+        invoiceEntity.setShipAddress(order.getReceiver().getShipAddress());
+        invoiceEntity.setShipAreaPath(order.getReceiver().getShipAreaPath());
+        invoiceEntity.setEmailAddress(param.getEmailAddress());
+
+        invoiceEntity.setMoney(new BigDecimal(param.getAmount()));
+        if(!this.save(invoiceEntity)){
+            throw new BusinessException(ErrorCode.ERROR_MSG);
+        }
     }
 }

+ 11 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/OrderItemServiceImpl.java

@@ -4,8 +4,12 @@ import com.fdkankan.order.entity.OrderItem;
 import com.fdkankan.order.mapper.IOrderItemMapper;
 import com.fdkankan.order.service.IOrderItemService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.user.vo.ResponseOrderItem;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
+import java.util.List;
+
 /**
  * <p>
  * 订单项表 服务实现类
@@ -17,4 +21,11 @@ import org.springframework.stereotype.Service;
 @Service
 public class OrderItemServiceImpl extends ServiceImpl<IOrderItemMapper, OrderItem> implements IOrderItemService {
 
+    @Resource
+    private IOrderItemMapper orderItemMapper;
+
+    @Override
+    public List<ResponseOrderItem> getByOrderId(Long orderId) {
+        return orderItemMapper.getByOrderId(orderId);
+    }
 }

+ 454 - 2
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/OrderServiceImpl.java

@@ -1,11 +1,50 @@
 package com.fdkankan.order.service.impl;
 
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.common.constant.*;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.common.util.DateUtil;
+import com.fdkankan.common.util.FileSizeUtil;
+import com.fdkankan.common.util.FileUtils;
+import com.fdkankan.common.util.NumberUtils;
+import com.fdkankan.goods.common.SkuCache;
+import com.fdkankan.goods.entity.*;
+import com.fdkankan.goods.service.*;
+import com.fdkankan.goods.vo.ResponseGoods;
+import com.fdkankan.goods.vo.ResponseGoodsSku;
+import com.fdkankan.order.constant.OrderEnum;
+import com.fdkankan.order.entity.Invoice;
 import com.fdkankan.order.entity.Order;
+import com.fdkankan.order.entity.OrderItem;
 import com.fdkankan.order.mapper.IOrderMapper;
-import com.fdkankan.order.service.IOrderService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.order.service.*;
+import com.fdkankan.order.vo.ResponseCommerceOrder;
+import com.fdkankan.order.vo.ResponseExpansionOrder;
+import com.fdkankan.pay.alipay.sdk.AlipayService;
+import com.fdkankan.pay.wx.WXPayDefaultConfig;
+import com.fdkankan.pay.wx.sdk.WXPay;
+import com.fdkankan.pay.wx.sdk.WXPayConstants;
+import com.fdkankan.user.entity.SSOUser;
+import com.fdkankan.user.entity.UserIncrement;
+import com.fdkankan.user.request.*;
+import com.fdkankan.user.service.IUserIncrementService;
+import com.fdkankan.user.service.IUserService;
+import com.fdkankan.user.vo.*;
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
 /**
  * <p>
  * 订单表 服务实现类
@@ -17,4 +56,417 @@ import org.springframework.stereotype.Service;
 @Service
 public class OrderServiceImpl extends ServiceImpl<IOrderMapper, Order> implements IOrderService {
 
+    @Resource
+    private RedisTemplate<String,String> redisTemplate;
+    @Autowired
+    private IOrderItemService orderItemService;
+    @Autowired
+    private IInvoiceService invoiceService;
+    @Autowired
+    private IUserService userService;
+    @Autowired
+    private ICartService cartService;
+    @Autowired
+    private IGoodsService goodsService;
+    @Autowired
+    private IGoodsSkuService goodsSkuService;
+    @Autowired
+    private ICameraService cameraService;
+    @Autowired
+    private ICameraDetailService cameraDetailService;
+    @Autowired
+    private ICameraSpaceService cameraSpaceService;
+    @Autowired
+    private IVirtualOrderService virtualOrderService;
+    @Autowired
+    private IExpansionOrderService expansionOrderService;
+    @Autowired
+    private ICommerceOrderService commerceOrderService;
+    @Autowired
+    private IIncrementOrderService incrementOrderService;
+    @Autowired
+    private IDownloadOrderService downloadOrderService;
+    @Resource
+    private AlipayService alipayService;
+    @Autowired
+    private IUserIncrementService userIncrementService;
+
+    @Override
+    public ResponseOrder getOrderDetail(Long orderId) {
+        Order order = this.getById(orderId);
+        ResponseOrder responseOrder = new ResponseOrder();
+        if(order == null){
+            return responseOrder;
+        }
+        BeanUtils.copyProperties(order,responseOrder);
+
+        List<ResponseOrderItem> responseOrderItems =orderItemService.getByOrderId(orderId);
+        responseOrder.setOrderItems(responseOrderItems);
+
+        Invoice invoice = invoiceService.getByOrderId(orderId);
+        if(invoice != null){
+            ResponseInvoice responseInvoice = new ResponseInvoice();
+            BeanUtils.copyProperties(invoice, responseInvoice);
+            responseOrder.setInvoice(responseInvoice);
+        }
+        return responseOrder;
+    }
+
+    @Override
+    public Page<ResponseOrder> getOrders(RequestOrder param, String token) {
+        SSOUser ssoUser = userService.getSSOUserByToken(token);
+        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(Order::getUserId,ssoUser.getId());
+        queryWrapper.lambda().eq(Order::getPaymentStatus, OrderEnum.PaymentStatus.paid);
+        queryWrapper.lambda().orderByDesc(Order::getOrderTime);
+        Page<Order> orderPage = this.page(new Page<>(param.getPageNum(),param.getPageSize()), queryWrapper);
+
+        List<ResponseOrder> voList = orderPage.getRecords().parallelStream().map(order -> {
+            ResponseOrder vo = new ResponseOrder();
+            BeanUtils.copyProperties(order, vo);
+            return vo;
+        }).collect(Collectors.toList());
+        Page<ResponseOrder> voPage = new Page<ResponseOrder>(param.getPageNum(), param.getPageSize());
+        voPage.setTotal(orderPage.getTotal());
+        voPage.setRecords(voList);
+        return voPage;
+    }
+
+    @Override
+    public String cancelOrder(RequestOrder param, String token) {
+        Order order = this.getById(param.getOrderId());
+        order.setOrderStatus(OrderEnum.OrderStatus.invalid.name());
+        order.setRecStatus("I");
+        if(!this.updateById(order)){
+            throw  new BusinessException(ErrorCode.ERROR_MSG);
+        }
+        return ServerCode.SUCCESS.message();
+    }
+
+    @Override
+    public String receiptOrder(RequestOrder param, String token) {
+        Order orderEntity = this.getById(param.getOrderId());
+        orderEntity.setShippingStatus(OrderEnum.ShippingStatus.received.name());
+        orderEntity.setOrderStatus(OrderEnum.OrderStatus.completed.name());
+        if(!this.updateById(orderEntity)){
+            throw  new BusinessException(ErrorCode.ERROR_MSG);
+        }
+        return ServerCode.SUCCESS.message();
+    }
+
+    @Override
+    public ResponseInvoice getInvoiceDetail(RequestOrder param, String token) {
+        List<ResponseOrderItem> responseOrderItems = orderItemService.getByOrderId(param.getOrderId());
+        StringBuilder sb = new StringBuilder();
+        if (responseOrderItems != null && responseOrderItems.size() > 0){
+            for (ResponseOrderItem vo : responseOrderItems){
+                sb.append(vo.getGoodsCount()).append("*").append(vo.getGoodsName()).append("  ");
+            }
+        }
+        Invoice invoice = invoiceService.getByOrderId(param.getOrderId());
+        ResponseInvoice responseInvoice= new ResponseInvoice();
+        if (invoice != null){
+            responseInvoice = new ResponseInvoice();
+            responseInvoice.setType(invoice.getType());
+            responseInvoice.setTitle(invoice.getTitle());
+            responseInvoice.setDescription(sb.toString());
+        }
+        return responseInvoice;
+    }
+
+    @Override
+    public ResponseOrder placeOrder(RequestPlaceOrder order, String token) {
+        SSOUser ssoUser = userService.getSSOUserByToken(token);
+        // 删除购物车
+        String cartIdsStr = "";
+        RequestCart[] carts = order.getGoods();
+        for (int i = 0; i < carts.length; i++){
+            cartIdsStr += carts[i].getId();
+            if (i != carts.length - 1) cartIdsStr += ",";
+        }
+        RequestCart param = new RequestCart();
+        param.setIds(cartIdsStr);
+        cartService.removeCarts(param,token);
+        // 下单
+        List<OrderItem> orderItemEntities = new ArrayList<>();
+        OrderItem orderItemEntity = null;
+        int goodsTotalCount = 0;
+        BigDecimal goodsAmount = new BigDecimal(0);
+
+        for(RequestCart requestCart : order.getGoods()){
+            goodsTotalCount += requestCart.getGoodsCount();
+            ResponseGoods responseGoods = goodsService.getByGoodsId(requestCart.getGoodsId());
+            ResponseGoodsSku sku = goodsSkuService.getVoBySkuSn(requestCart.getSkuSn());
+            if(responseGoods == null || sku == null){
+                continue;
+            }
+            orderItemEntity = new OrderItem();
+            orderItemEntity.setExpressNum(null);
+            orderItemEntity.setGoodsPrice(order.getAbroad() == 0 ? sku.getPrice() : sku.getDollarPrice());
+            orderItemEntity.setGoodsId(requestCart.getGoodsId());
+            orderItemEntity.setShippingStatus(OrderEnum.ShippingStatus.unshipped.name());
+            orderItemEntity.setExpressName("顺丰速运");
+            orderItemEntity.setGoodsCount(requestCart.getGoodsCount());
+            orderItemEntity.setGoodsName(responseGoods.getName());
+            orderItemEntity.setGoodsSn(responseGoods.getGoodsSn());
+            if (StringUtils.isNotEmpty(requestCart.getSkuSn())){
+                orderItemEntity.setSkuSn(requestCart.getSkuSn());
+            }
+            orderItemEntities.add(orderItemEntity);
+            goodsAmount = goodsAmount.add(orderItemEntity.getGoodsPrice().multiply(new BigDecimal(orderItemEntity.getGoodsCount())));
+        }
+        Order orderEntity = new Order();
+        orderEntity.setOrderSn(NumberUtils.getOrderSn());
+        orderEntity.setOrderTime(new Date());
+        orderEntity.setOrderStatus(OrderEnum.OrderStatus.unprocessed.name());
+        orderEntity.setPaymentStatus(OrderEnum.PaymentStatus.unpaid.name());
+        orderEntity.setShippingStatus(OrderEnum.ShippingStatus.unshipped.name());
+        orderEntity.setPaymentTypeName(order.getPayType());
+        orderEntity.setUserId(ssoUser.getId());
+        orderEntity.setGoodsTotalCount(goodsTotalCount);
+        orderEntity.setGoodsAmount(goodsAmount);
+        orderEntity.setTotalAmount(goodsAmount);
+        orderEntity.setPaidAmount(BigDecimal.ZERO);
+        orderEntity.setExpressAmount(BigDecimal.ZERO);
+        orderEntity.setDeliveryTypeName("快递运输");
+        if (order.getReceiver() != null){
+            orderEntity.setShipAddress(order.getReceiver().getShipAddress());
+            orderEntity.setShipAreaPath(order.getReceiver().getShipAreaPath());
+            orderEntity.setShipMobile(order.getReceiver().getShipMobile());
+            orderEntity.setShipName(order.getReceiver().getShipName());
+        }
+        orderEntity.setAbroad(order.getAbroad());
+        if(!this.save(orderEntity)){
+            throw new BusinessException(ErrorCode.ERROR_MSG);
+        }
+        for (OrderItem itemEntity : orderItemEntities) {
+            itemEntity.setOrderId(orderEntity.getId());
+            if(!orderItemService.save(itemEntity)){
+                throw new BusinessException(ErrorCode.ERROR_MSG);
+            }
+        }
+        ResponseOrder responseOrder = new ResponseOrder();
+        BeanUtils.copyProperties(orderEntity, responseOrder);
+
+        // 添加发票信息
+        if (order.getInvoice() != null && StringUtils.isNotEmpty(order.getInvoice().getInvoiceType())){
+            order.setOrderId(orderEntity.getId());
+            order.getInvoice().setAmount(responseOrder.getTotalAmount().toString());
+            invoiceService.saveInvoiceByOrder(ssoUser.getId(),order);
+        }
+        return responseOrder;
+    }
+
+    @Override
+    public ResponseVirtualOrder rechargeOrder(RequestCamera param, String token) {
+        SSOUser ssoUser = userService.getSSOUserByToken(token);
+        Camera camera = cameraService.getById(param.getCameraId());
+        if(camera == null){
+            throw new BusinessException(CameraConstant.FAILURE_6003);
+        }
+        CameraDetail cameraDetail = cameraDetailService.getByCameraId(param.getCameraId());
+        int sub = Integer.valueOf(cameraDetail.getBalance()) + param.getPoints();
+        if (sub > Constant.MAXPOINTS) {
+            throw new BusinessException(CameraConstant.FAILURE_6004);
+        }
+        return virtualOrderService.saveByCamera(ssoUser.getId(),param);
+    }
+
+    @Override
+    public ResponseExpansionOrder expansionOrder(RequestExpansionOrder order, String token) {
+        SSOUser ssoUser = userService.getSSOUserByToken(token);
+        //支付美金,只能paypal支付
+        if(order.getAbroad() == 1 && order.getPayType() != 2){
+            throw new BusinessException(OrderConstant.FAILURE_CODE_8004, OrderConstant.FAILURE_MSG_8004);
+        }
+        ResponseGoodsSku sku = goodsSkuService.getVoBySkuSn(order.getSkuSn());
+        if(sku == null ){
+            throw new BusinessException(ErrorCode.ERROR_MSG);
+        }
+        int delay = 0;
+        int dateNum = 0;
+        double spaceSize = 0;
+        //基础容量10G
+        long baseSpace = 10;
+        List<CameraSpace> cameraSpaceEntityList = cameraSpaceService.getListByCameraId(order.getCameraId());
+        for(CameraSpace cameraSpaceEntity : cameraSpaceEntityList){
+            dateNum = DateUtil.daysBetween(new Date(), cameraSpaceEntity.getSpaceEndTime());
+            if(dateNum > 0){
+                spaceSize = FileSizeUtil.formetFileSize(cameraSpaceEntity.getSpace(), FileSizeUtil.SIZETYPE_GB);
+                //时间换算,(剩余天数*旧容量)/新容量 = 延期天数
+                if((dateNum * (spaceSize - baseSpace)) % (sku.getUnitSize() - baseSpace) > 0){
+                    //无法整除天数+1
+                    delay += ((dateNum * (spaceSize - baseSpace)) / (sku.getUnitSize() - baseSpace)) + 1;
+                }else {
+                    delay += (dateNum * (spaceSize - baseSpace)) / (sku.getUnitSize() - baseSpace);
+                }
+            }
+        }
+        return expansionOrderService.saveByOrderParam(ssoUser.getId(), order, order.getAbroad() == 0 ?  sku.getPrice() : sku.getDollarPrice(),
+                sku.getUnit(), sku.getUnitSize(), sku.getMonth(), delay);
+    }
+
+    @Override
+    public ResponseCommerceOrder commerceOrder(RequestCommerceOrder param, String token) {
+        SSOUser ssoUser = userService.getSSOUserByToken(token);
+        ResponseGoodsSku sku = goodsSkuService.getVoBySkuSn(param.getSkuSn());
+        return commerceOrderService.saveByOrderParam(ssoUser.getId(), param, param.getAbroad() == 0 ?  sku.getPrice() : sku.getDollarPrice());
+    }
+
+    @Override
+    public ResponseIncrementOrder incrementOrder(RequestIncrementOrder order, String token) {
+        SSOUser ssoUser = userService.getSSOUserByToken(token);
+        //支付美金,只能paypal支付
+        if(order.getAbroad() == 1 && order.getPayType() != 2){
+            throw new BusinessException(OrderConstant.FAILURE_CODE_8004, OrderConstant.FAILURE_MSG_8004);
+        }
+        ResponseGoodsSku sku = goodsSkuService.getVoBySkuSn(order.getSkuSn());
+        return incrementOrderService.saveByOrderParam(ssoUser.getId(), order, order.getAbroad() == 0 ?  sku.getPrice() : sku.getDollarPrice());
+    }
+
+    @Override
+    public ResponseDownloadOrder downloadOrder(RequestIncrementOrder order, String token) {
+        SSOUser ssoUser = userService.getSSOUserByToken(token);
+        //支付美金,只能paypal支付
+        if(order.getAbroad() == 1 && order.getPayType() != 2){
+            throw new BusinessException(OrderConstant.FAILURE_CODE_8004, OrderConstant.FAILURE_MSG_8004);
+        }
+        ResponseGoodsSku sku = goodsSkuService.getVoBySkuSn(order.getSkuSn());
+        return downloadOrderService.saveByOrderParam(ssoUser.getId(), order, order.getAbroad() == 0 ?  sku.getPrice() : sku.getDollarPrice());
+    }
+
+    @Override
+    public Boolean queryOrderStatus(RequestVirtualOrder order, String token) throws Exception{
+        Boolean success = false;
+        String orderSn = order.getOrderSn();
+        switch (order.getOrderType()){
+            case 0:
+                orderSn += "_entity";break;
+            case 1:
+                orderSn += "_recharge";break;
+            case 2:
+                orderSn += "_expansion";break;
+            case 3:
+                orderSn += "_commerce";break;
+            case 4:
+                orderSn += "_increment";break;
+            case 5:
+                orderSn += "_download";break;
+        }
+        switch (order.getPayType()){
+            // 微信
+            case 0:
+                String orderSnE = redisTemplate.opsForValue().get(orderSn);
+                log.warn("out_trade_no:" + orderSnE);
+                if (StringUtils.isNotEmpty(orderSnE)){
+                    Map<String, String> data = new HashMap<String, String>();
+                    data.put("out_trade_no", orderSnE);
+                    WXPayDefaultConfig config = new WXPayDefaultConfig();
+                    WXPay wxPay = new WXPay(config);
+                    Map<String, String> resp = wxPay.orderQuery(data);
+                    if (resp.get("trade_state") != null && resp.get("trade_state").equals(WXPayConstants.SUCCESS)) {
+                        redisTemplate.delete(orderSnE);
+                        String pngPath = ConstantFilePath.BASE_PATH + ConstantFilePath.WEIXIN_QRCODE_FOLDER + orderSn + ".png";
+                        FileUtils.deleteFile(pngPath);
+                        success = true;
+                    }
+                }
+                break;
+            // 支付宝
+            case 1:
+                log.warn("alipay out_trade_no:" + orderSn);
+                String type = alipayService.tradeQuery(orderSn);
+                log.warn("alipay type:" + type);
+                if ("SUCCESS".equals(type)){
+                    success = true;
+                }
+                break;
+            // paypal
+            case 2:
+                orderSn = orderSn.split("_")[0];
+                log.warn("paypal out_trade_no:" + orderSn);
+                Order byOrderSn = this.getByOrderSn(orderSn);
+                if (byOrderSn!=null && OrderEnum.PaymentStatus.paid.name().equals(byOrderSn.getPaymentStatus())){
+                    success = true;
+                }
+                break;
+        }
+        return success;
+    }
+
+    private Order getByOrderSn(String orderSn) {
+        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(Order::getOrderSn,orderSn);
+        List<Order> list = this.list(queryWrapper);
+        if(list == null || list.size()<=0){
+            return null;
+        }
+        return list.get(0);
+    }
+
+    @Override
+    public ResponseGoods getExpansionPrice(RequestCamera camera, String token) {
+        String skuStr = SkuCache.skusMap.get(String.valueOf(camera.getDateType()));
+        if (StringUtils.isEmpty(skuStr)){
+            skuStr = SkuCache.skusMap.get("1");
+        }
+        String[] skus = skuStr.split(",");
+        List<ResponseGoodsSku> skusList = new ArrayList<>();
+        Long goodsId = null;
+        for (String sku : skus){
+            GoodsSku goodsSkuEntity = goodsSkuService.getBySkuSn(sku);
+            if (goodsSkuEntity != null){
+                ResponseGoodsSku responseGoodsSku = new ResponseGoodsSku();
+                BeanUtils.copyProperties(goodsSkuEntity, responseGoodsSku);
+                if (StringUtils.isNotEmpty(responseGoodsSku.getDescription())){
+                    try {
+                        JSONObject o = JSONObject.parseObject(responseGoodsSku.getDescription());
+                        responseGoodsSku.setUnit(o.getString("容量"));
+                    }catch (Exception e){}
+                }
+                skusList.add(responseGoodsSku);
+                goodsId = goodsSkuEntity.getGoodsId();
+            }
+        }
+        Goods goodsEntity = goodsService.getById(goodsId);
+        ResponseGoods responseGoods = new ResponseGoods();
+        BeanUtils.copyProperties(goodsEntity, responseGoods);
+        responseGoods.setSkuList(skusList);
+        DateTime dateTime = new DateTime();
+        //camera.getDateType() = 2 为年,其余为月
+        if (camera.getDateType() != 2){
+            dateTime = dateTime.plusDays(31 * skusList.get(0).getMonth());
+        }else{
+            dateTime = dateTime.plusYears(1);
+        }
+        responseGoods.setDeadLine(dateTime.toDate().getTime());
+        return responseGoods;
+    }
+
+    @Override
+    public ResponseGoodsSku getIncrementOrDownloadPrice(RequestCamera camera, String token) {
+        if(camera.getDateType() == null){
+            throw new BusinessException(ErrorCode.MISSING_REQUIRED_PARAMETERS);
+        }
+
+        if(camera.getDateType() != 5 && camera.getDateType() != 6){
+            throw new BusinessException(ErrorCode.MISSING_REQUIRED_PARAMETERS);
+        }
+
+        DateTime dateTime = new DateTime();
+
+        if(camera.getUserIncrementId() != null){
+            UserIncrement userIncrementEntity = userIncrementService.getById(camera.getUserIncrementId());
+            if(userIncrementEntity != null && userIncrementEntity.getIncrementEndTime().getTime() > new Date().getTime()){
+                dateTime = new DateTime(userIncrementEntity.getIncrementEndTime());
+            }
+        }
+
+        ResponseGoodsSku responseGoodsSku = goodsSkuService.getIncrementOrDownloadPrice(camera);
+
+        //1年期限
+        dateTime = dateTime.plusYears(1);
+        responseGoodsSku.setDeadLine(dateTime.toDate().getTime());
+        return responseGoodsSku;
+    }
 }

+ 28 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/order/service/impl/VirtualOrderServiceImpl.java

@@ -5,13 +5,17 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fdkankan.agent.constant.AgentConstant;
 import com.fdkankan.agent.vo.AgentVo;
 import com.fdkankan.agent.vo.ResponseAgentCamera;
+import com.fdkankan.common.constant.Constant;
 import com.fdkankan.common.constant.ErrorCode;
 import com.fdkankan.common.exception.BusinessException;
 import com.fdkankan.common.util.NumberUtils;
 import com.fdkankan.order.entity.VirtualOrder;
 import com.fdkankan.order.mapper.IVirtualOrderMapper;
 import com.fdkankan.order.service.IVirtualOrderService;
+import com.fdkankan.user.request.RequestCamera;
+import com.fdkankan.user.vo.ResponseVirtualOrder;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
@@ -184,4 +188,28 @@ public class VirtualOrderServiceImpl extends ServiceImpl<IVirtualOrderMapper, Vi
         return vo;
     }
 
+    @Override
+    public ResponseVirtualOrder saveByCamera(Long userId, RequestCamera camera) {
+        VirtualOrder virtualOrderEntity = new VirtualOrder();
+        virtualOrderEntity.setCameraId(camera.getCameraId());
+        virtualOrderEntity.setPayType(camera.getPayType());
+//        if (camera.getAbroad().intValue() == 1){
+////            virtualOrderEntity.setAmount(new BigDecimal(camera.getPoints()).multiply(new BigDecimal(0.145)));
+////        }else{
+////            virtualOrderEntity.setAmount(new BigDecimal(camera.getPoints()));
+////        }
+        virtualOrderEntity.setAmount(new BigDecimal(camera.getPoints()));
+        virtualOrderEntity.setPoints(camera.getPoints());
+        virtualOrderEntity.setOrderSn(NumberUtils.getOrderSn());
+        virtualOrderEntity.setUserId(userId);
+        virtualOrderEntity.setStatus(1);
+        virtualOrderEntity.setPayStatus(-1);
+        virtualOrderEntity.setBody(Constant.PAY_SUBJECT);
+        virtualOrderEntity.setAbroad(camera.getAbroad());
+        virtualOrderEntity.setTradeTime(new Date());
+        this.save(virtualOrderEntity);
+        ResponseVirtualOrder responseVirtualOrder = new ResponseVirtualOrder();
+        BeanUtils.copyProperties(virtualOrderEntity, responseVirtualOrder);
+        return responseVirtualOrder;
+    }
 }

+ 58 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/order/vo/ResponseCommerceOrder.java

@@ -0,0 +1,58 @@
+package com.fdkankan.order.vo;
+
+import com.fdkankan.common.request.RequestBase;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class ResponseCommerceOrder extends RequestBase implements Serializable {
+
+    private static final long serialVersionUID = 4972396312239681244L;
+
+    private Long id;
+    /**
+     * 订单号
+     */
+    private String orderSn;
+    /**
+     * 金额
+     */
+    private BigDecimal amount;
+    /**
+     * 支付宝的交易号或者微信支付订单号
+     */
+    private String number;
+    /**
+     * 付款方式,0表示微信,1表示支付宝,2表示paypal,3表示其他
+     */
+    private int payType;
+    /**
+     * 状态,0或-1表示消费失败,1表示成功
+     */
+    private int payStatus;
+    /**
+     * 交易时间
+     */
+    private Date tradeTime;
+    /**
+     * 用户表t_user的id,空表示后台管理员添加
+     */
+    private Long userId;
+    /**
+     * 0表示国内订单,1表示国外订单
+     */
+    private int abroad;
+    /**
+     * 0表示年,1表示月
+     */
+    private int commerceType;
+    /**
+     * 数量
+     */
+    private int count;
+
+    private Long cameraId;
+}

+ 104 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/order/vo/ResponseExpansionOrder.java

@@ -0,0 +1,104 @@
+package com.fdkankan.order.vo;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.fdkankan.common.constant.Constant;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+
+@Data
+public class ResponseExpansionOrder implements Serializable {
+
+    private static final long serialVersionUID = 4972396312239681244L;
+
+    private Long id;
+    /**
+     * 订单号
+     */
+    private String orderSn;
+    /**
+     * 金额
+     */
+    private BigDecimal amount;
+    /**
+     * 支付宝的交易号或者微信支付订单号
+     */
+    private String number;
+    /**
+     * 付款方式,0表示微信,1表示支付宝,2表示paypal,3表示其他
+     */
+    private int payType;
+    /**
+     * 状态,0或-1表示消费失败,1表示成功
+     */
+    private int payStatus;
+    /**
+     * 交易时间
+     */
+    private Date tradeTime;
+    /**
+     * 用户表t_user的id,空表示后台管理员添加
+     */
+    private Long userId;
+
+    private Long cameraId;
+    /**
+     * 0表示国内订单,1表示国外订单
+     */
+    private int abroad;
+    /**
+     * 容量单位,"GB", "TB", "PB"
+     */
+    private String unit;
+    /**
+     * 容量大小
+     */
+    private int unitSize;
+    /**
+     * 期限,年为单位
+     */
+    private int years;
+
+    /**
+     * 期限,年为单位
+     */
+    private int month;
+
+    /**
+     * 延期,天为单位
+     */
+    private int delay;
+
+    public BigInteger getSpace(){
+        if ("GB".equals(getUnit())){
+            return new BigInteger(Constant.EXPANSION_SPACE_VALUE_1G).multiply(new BigInteger(unitSize + ""));
+        }else if ("TB".equals(getUnit())){
+            return new BigInteger(Constant.EXPANSION_SPACE_VALUE_1T).multiply(new BigInteger(unitSize + ""));
+        }else if ("PB".equals(getUnit())){
+            return new BigInteger(Constant.EXPANSION_SPACE_VALUE_1P).multiply(new BigInteger(unitSize + ""));
+        }
+        return new BigInteger("0");
+    }
+
+    private String childName;
+
+    private BigInteger space;
+    /**
+     * 生效时间
+     */
+    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
+    private Date spaceStartTime;
+    /**
+     * 结束时间
+     */
+    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
+    private Date spaceEndTime;
+
+    private String validDate;
+
+    private int status;
+
+}

+ 11 - 7
4dkankan-center-platform/src/main/java/com/fdkankan/user/controller/api/UserInvoiceController.java

@@ -3,8 +3,7 @@ package com.fdkankan.user.controller.api;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.fdkankan.order.service.IInvoiceService;
 import com.fdkankan.user.request.RequestInvoice;
-import com.fdkankan.user.service.IUserIncrementService;
-import com.fdkankan.user.vo.ResponseUserIncrement;
+import com.fdkankan.user.vo.ResponseInvoice;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -26,27 +25,30 @@ public class UserInvoiceController {
     /**
      * 获得可开发票的最高额度
      * cameraId     设备id
+     * @return
      */
     @RequestMapping(value = "/max", method = RequestMethod.POST)
-    public String getMaxInvoice(@RequestBody RequestInvoice param, @RequestHeader String token) throws Exception {
+    public Integer getMaxInvoice(@RequestBody RequestInvoice param, @RequestHeader String token) throws Exception {
         return invoiceService.getMaxInvoice(param,token);
     }
 
     /**
      * 获取用户发票记录
      * cameraId       相机id
+     * @return
      */
     @RequestMapping(value = "/list", method = RequestMethod.POST)
-    public String list(@RequestBody RequestInvoice param, @RequestHeader String token) throws Exception {
+    public Page<ResponseInvoice> list(@RequestBody RequestInvoice param, @RequestHeader String token) throws Exception {
         return invoiceService.listInvoice(param,token);
     }
 
     /**
      * 获取用户发票记录
      * invoiceType      发票类型,2表示增值税普通发票,3表示增值税专用发票
+     * @return
      */
     @RequestMapping(value = "/mine", method = RequestMethod.POST)
-    public String mine(@RequestBody RequestInvoice param, @RequestHeader String token) throws Exception {
+    public ResponseInvoice mine(@RequestBody RequestInvoice param, @RequestHeader String token) throws Exception {
         return invoiceService.mineInvoice(param,token);
     }
 
@@ -69,9 +71,10 @@ public class UserInvoiceController {
     /**
      * 获取发票详情
      * invoiceId          发票id
+     * @return
      */
     @RequestMapping(value = "/detail", method = RequestMethod.POST)
-    public String detail(@RequestBody RequestInvoice param, @RequestHeader String token) throws Exception {
+    public ResponseInvoice detail(@RequestBody RequestInvoice param, @RequestHeader String token) throws Exception {
         return invoiceService.detailInvoice(param,token);
     }
 
@@ -141,9 +144,10 @@ public class UserInvoiceController {
      * shipAreaPath     收货地区路径
      * shipAddress      收货地址
      * shipMobile       收货手机
+     * @return
      */
     @RequestMapping(value = "/open", method = RequestMethod.POST)
-    public String open(@RequestBody RequestInvoice param, @RequestHeader String token) throws Exception {
+    public ResponseInvoice open(@RequestBody RequestInvoice param, @RequestHeader String token) throws Exception {
         return invoiceService.openInvoice(param,token);
     }
 

+ 175 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/user/controller/api/UserOrderController.java

@@ -0,0 +1,175 @@
+package com.fdkankan.user.controller.api;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fdkankan.goods.vo.ResponseGoods;
+import com.fdkankan.goods.vo.ResponseGoodsSku;
+import com.fdkankan.order.service.IOrderService;
+import com.fdkankan.order.vo.ResponseCommerceOrder;
+import com.fdkankan.order.vo.ResponseExpansionOrder;
+import com.fdkankan.user.request.*;
+import com.fdkankan.user.vo.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 个人中心-增值发票
+ */
+@RestController
+@RequestMapping("/api/user/order")
+public class UserOrderController {
+
+    private static Logger log = LoggerFactory.getLogger("programLog");
+
+    @Autowired
+    private IOrderService orderService;
+
+
+    /**
+     * 获取用户订单
+     * type     0-待支付,1-待发货,2-已发货,空-全部
+     */
+    @RequestMapping(value = "/list", method = RequestMethod.POST)
+    public Page<ResponseOrder> getOrders(@RequestBody RequestOrder param, @RequestHeader String token) throws Exception {
+        return orderService.getOrders(param,token);
+    }
+    /**
+     * 获取订单详情
+     * orderId     订单id
+     */
+    @RequestMapping(value = "/detail", method = RequestMethod.POST)
+    public ResponseOrder getOrderDetail(@RequestBody RequestOrder param, @RequestHeader String token) throws Exception {
+        return orderService.getOrderDetail(param.getOrderId());
+    }
+    /**
+     * 取消订单
+     * orderId     订单id
+     */
+    @RequestMapping(value = "/cancel", method = RequestMethod.POST)
+    public String cancelOrder(@RequestBody RequestOrder param, @RequestHeader String token) throws Exception {
+        return orderService.cancelOrder(param,token);
+    }
+    /**
+     * 确认收货
+     * orderId     订单id
+     */
+    @RequestMapping(value = "/receipt", method = RequestMethod.POST)
+    public String receiptOrder(@RequestBody RequestOrder param, @RequestHeader String token) throws Exception {
+        return orderService.receiptOrder(param,token);
+    }
+    /**
+     * 获取订单发票信息
+     * orderId     订单id
+     * @return
+     */
+    @RequestMapping(value = "/getInvoiceDetail", method = RequestMethod.POST)
+    public ResponseInvoice getInvoiceDetail(@RequestBody RequestOrder param, @RequestHeader String token) throws Exception {
+        return orderService.getInvoiceDetail(param,token);
+    }
+    /**
+     * 确认订单 购物提交订单
+     * goods     商品信息
+     * abroad     0表示国内订单,1表示国外订单
+     * orderId     订单id
+     * receiver     收货人信息
+     * payType     付款方式,0表示微信,1表示支付宝,2表示paypal,3表示其他,4表示货到付款
+     * invoice     发票信息
+     * @return
+     */
+    @RequestMapping(value = "/placeOrder", method = RequestMethod.POST)
+    public ResponseOrder placeOrder(@RequestBody RequestPlaceOrder param, @RequestHeader String token) throws Exception {
+        return orderService.placeOrder(param,token);
+    }
+    /**
+     * 充值提交订单
+     * cameraId     相机id
+     * points     重置点数
+     * @return
+     */
+    @RequestMapping(value = "/rechargeOrder", method = RequestMethod.POST)
+    public ResponseVirtualOrder rechargeOrder(@RequestBody RequestCamera param, @RequestHeader String token) throws Exception {
+        return orderService.rechargeOrder(param,token);
+    }
+    /**
+     * 扩容提交订单
+     * cameraId     相机id
+     * payType     付款方式,0表示微信,1表示支付宝,2表示paypal,3表示其他
+     * skuSn     商品编码
+     * abroad     0表示国内订单,1表示国外订单
+     * @return
+     */
+    @RequestMapping(value = "/expansionOrder", method = RequestMethod.POST)
+    public ResponseExpansionOrder expansionOrder(@RequestBody RequestExpansionOrder param, @RequestHeader String token) throws Exception {
+        return orderService.expansionOrder(param,token);
+    }
+    /**
+     * 商业相机提交订单
+     * cameraId     相机id
+     * payType     付款方式,0表示微信,1表示支付宝,2表示paypal,3表示其他
+     * skuSn     商品编码
+     * count     数量
+     * abroad     0表示国内订单,1表示国外订单
+     * @return
+     */
+    @RequestMapping(value = "/commerceOrder", method = RequestMethod.POST)
+    public ResponseCommerceOrder commerceOrder(@RequestBody RequestCommerceOrder param, @RequestHeader String token) throws Exception {
+        return orderService.commerceOrder(param,token);
+    }
+    /**
+     * 增值权益提交订单
+     * cameraId     相机id
+     * payType     付款方式,0表示微信,1表示支付宝,2表示paypal,3表示其他
+     * skuSn     商品编码
+     * count     数量
+     * abroad     0表示国内订单,1表示国外订单
+     * @return
+     */
+    @RequestMapping(value = "/incrementOrder", method = RequestMethod.POST)
+    public ResponseIncrementOrder incrementOrder(@RequestBody RequestIncrementOrder param, @RequestHeader String token) throws Exception {
+        return orderService.incrementOrder(param,token);
+    }
+    /**
+     * 下载场景提交订单
+     * payType     付款方式,0表示微信,1表示支付宝,2表示paypal,3表示其他
+     * skuSn     商品编码
+     * count     数量
+     * abroad     0表示国内订单,1表示国外订单
+     * @return
+     */
+    @RequestMapping(value = "/downloadOrder", method = RequestMethod.POST)
+    public ResponseDownloadOrder downloadOrder(@RequestBody RequestIncrementOrder param, @RequestHeader String token) throws Exception {
+        return orderService.downloadOrder(param,token);
+    }
+    /**
+     * 交易查询
+     * orderSn      订单编码
+     * payType     付款方式,0表示微信,1表示支付宝,2表示paypal,3表示其他
+     * orderType     订单类型,0表示购物,1表示点数充值,2表示扩充容量
+     * @return
+     */
+    @RequestMapping(value = "/queryOrderStatus", method = RequestMethod.POST)
+    public Boolean queryOrderStatus(@RequestBody RequestVirtualOrder param, @RequestHeader String token) throws Exception {
+        return orderService.queryOrderStatus(param,token);
+    }
+    /**
+     * 获取扩容价格
+     * dateType      日期价格类型,2为年其余为月
+     * @return
+     */
+    @RequestMapping(value = "/getExpansionPrice", method = RequestMethod.POST)
+    public ResponseGoods getExpansionPrice(@RequestBody RequestCamera param, @RequestHeader String token) throws Exception {
+        return orderService.getExpansionPrice(param,token);
+    }
+    /**
+     * 获取增值权益或场景下载价格
+     * dateType      5增值权益,6场景下载
+     * @return
+     */
+    @RequestMapping(value = "/getIncrementOrDownloadPrice", method = RequestMethod.POST)
+    public ResponseGoodsSku getIncrementOrDownloadPrice(@RequestBody RequestCamera param, @RequestHeader String token) throws Exception {
+        return orderService.getIncrementOrDownloadPrice(param,token);
+    }
+
+
+}

+ 33 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/user/request/RequestCommerceOrder.java

@@ -0,0 +1,33 @@
+package com.fdkankan.user.request;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class RequestCommerceOrder implements Serializable {
+
+    private static final long serialVersionUID = 6503649644925734099L;
+    /**
+     * 相机表id
+     */
+    private Long cameraId;
+    /**
+     * 0表示年,1表示月
+     */
+    private int commerceType;
+    /**
+     *  t_goods_sku的skuSn
+     */
+    private String skuSn;
+    /**
+     * 数量
+     */
+    private int count;
+    /**
+     * 付款方式,0表示微信,1表示支付宝,2表示paypal,3表示其他
+     */
+    private int payType;
+    // 0表示国内订单,1表示国外订单
+    private Integer abroad;
+}

+ 35 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/user/request/RequestExpansionOrder.java

@@ -0,0 +1,35 @@
+package com.fdkankan.user.request;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class RequestExpansionOrder implements Serializable {
+
+    private static final long serialVersionUID = 356275482753391583L;
+    /**
+     * 付款方式,0表示微信,1表示支付宝,2表示paypal,3表示其他
+     */
+    private int payType;
+    /**
+     * 容量单位,"GB", "TB", "PB"
+     */
+    private String unit;
+    /**
+     * 容量大小
+     */
+    private int unitSize;
+    /**
+     * 期限,年为单位
+     */
+    private int years;
+    /**
+     *  t_goods_sku的skuSn
+     */
+    private String skuSn;
+
+    private Long cameraId;
+    // 0表示国内订单,1表示国外订单
+    private Integer abroad;
+}

+ 44 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/user/request/RequestIncrementOrder.java

@@ -0,0 +1,44 @@
+package com.fdkankan.user.request;
+
+import com.fdkankan.common.request.RequestBase;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class RequestIncrementOrder extends RequestBase implements Serializable {
+
+    private static final long serialVersionUID = 6503649644925734099L;
+    /**
+     *  t_goods_sku的skuSn
+     */
+    private String skuSn;
+    /**
+     * 数量
+     */
+    private int count;
+    /**
+     * 付款方式,0表示微信,1表示支付宝,2表示paypal,3表示其他
+     */
+    private int payType;
+    // 0表示国内订单,1表示国外订单
+    private Integer abroad;
+
+    /**
+     * 用户增值权益id
+     */
+    private Long incrementId;
+
+    /**
+     * 场景码
+     */
+    private String sceneNum;
+
+    /**
+     * 场景名
+     */
+    private String sceneName;
+
+
+
+}

+ 31 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/user/request/RequestOrder.java

@@ -0,0 +1,31 @@
+package com.fdkankan.user.request;
+
+import com.fdkankan.common.request.RequestBase;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class RequestOrder extends RequestBase implements Serializable {
+
+    private static final long serialVersionUID = -8623405468613179650L;
+
+    private Long orderId;
+
+    private String orderItemIds;
+    //0-待支付,1-待发货,2-已发货,3-已完成,空-全部
+    private String type;
+    // 下单开始时间
+    private String startDate;
+    // 下单截止时间
+    private String endDate;
+
+    private String orderSn;
+
+    private String phoneNum;
+
+    private String expressName;
+
+    private String expressNum;
+
+}

+ 27 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/user/request/RequestPlaceOrder.java

@@ -0,0 +1,27 @@
+package com.fdkankan.user.request;
+
+import lombok.Data;
+
+import java.io.Serializable;
+// 下单
+@Data
+public class RequestPlaceOrder implements Serializable {
+
+    private static final long serialVersionUID = -8648579354113017724L;
+    // 商品信息
+    private RequestCart[] goods;
+    // 收货人信息
+    private RequestUser receiver;
+    // 发票
+    private RequestInvoice invoice;
+    // 付款方式,0表示微信,1表示支付宝,2表示paypal,3表示其他,4表示货到付款
+    private Integer payType;
+    // 订单表id
+    private Long orderId;
+    // 订单类型,0表示购物,1表示点数充值,2表示扩充容量
+    private Integer orderType;
+    // 0表示国内订单,1表示国外订单
+    private Integer abroad;
+    // 续费时扩容信息id
+    private Long spaceId;
+}

+ 46 - 0
4dkankan-center-platform/src/main/java/com/fdkankan/user/request/RequestVirtualOrder.java

@@ -0,0 +1,46 @@
+package com.fdkankan.user.request;
+
+import com.fdkankan.common.request.RequestBase;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class RequestVirtualOrder extends RequestBase implements Serializable {
+
+    private static final long serialVersionUID = -337253566487396505L;
+
+    private Long virtualOrderId;
+
+    private Long cameraId;
+
+    private String status;
+
+    private String body;
+
+    private String orderSn;
+
+    private BigDecimal amount;
+
+    private int points;
+
+    private String number;
+
+    private int payType;
+
+    private int payStatus;
+
+    private Date tradeTime;
+
+    private String sceneNum;
+
+    private int abroad;
+
+    private Long userId;
+    // 订单类型,0表示购物,1表示点数充值,2表示扩充容量
+    private Integer orderType;
+
+    private String childName;
+}

+ 41 - 0
4dkankan-common/src/main/java/com/fdkankan/common/constant/Constant.java

@@ -0,0 +1,41 @@
+package com.fdkankan.common.constant;
+
+public class Constant {
+
+    public static final String PAY_SUBJECT = "充值(四维看看Lite双目相机)";
+
+    public static final String EXPANSION_SUBJECT = "扩充容量";
+
+    public static final String COMMERCE_SUBJECT = "商业相机";
+
+    public static final String INCREMENT_SUBJECT = "会员权益";
+
+    public static final String DOWNLOAD_SUBJECT = "场景下载";
+
+    public static int MAXPOINTS = 100000;
+
+    public static int MONEY_SCENE = 99;
+
+    public static int MONEY_HOT = 9;
+    // 3G
+//    public static String ORDINARY_BASE_SPACE_VALUE = "3221225472";
+    // 30G
+//    public static String PROFESSION_BASE_SPACE_VALUE = "32212254720";
+    // 10G
+//    public static String COMMERCE_BASE_SPACE_VALUE = "10737418240";
+    // 1G
+//    public static String DEADLINE_SPACE_VALUE_MONTH =  "1073741824";
+    // 15G
+//    public static String DEADLINE_SPACE_VALUE_YEAR = "16106127360";
+
+    // 1GB
+    public static String EXPANSION_SPACE_VALUE_1G = "1073741824";
+    // 1TB
+    public static String EXPANSION_SPACE_VALUE_1T = "1099511627776";
+    // 1PB
+    public static String EXPANSION_SPACE_VALUE_1P = "1125899906842624";
+    // 八目相机基础容量10G
+    public static String CAMERA_BASE_SPACE_VALUE = "10737418240";
+    // 八目相机商业会员容量15G
+    public static String DEADLINE_SPACE_VALUE_YEAR = "16106127360";
+}

+ 17 - 0
4dkankan-common/src/main/java/com/fdkankan/common/constant/OrderConstant.java

@@ -0,0 +1,17 @@
+package com.fdkankan.common.constant;
+
+// 8001-9000 订单状态码
+public class OrderConstant {
+    public static final int FAILURE_CODE_8001 = 8001;
+    public static final String FAILURE_MSG_8001 = "订单不存在";
+
+
+    public static final int FAILURE_CODE_8002 = 8002;
+    public static final String FAILURE_MSG_8002 = "支付失败";
+
+    public static final int FAILURE_CODE_8003 = 8003;
+    public static final String FAILURE_MSG_8003 = "开票金额超过范围";
+
+    public static final int FAILURE_CODE_8004 = 8004;
+    public static final String FAILURE_MSG_8004 = "支付方式异常";
+}

+ 117 - 0
4dkankan-pay/pom.xml

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <packaging>jar</packaging>
+
+    <parent>
+        <artifactId>4dkankan-parent</artifactId>
+        <groupId>com.fdkankan</groupId>
+        <version>2.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>4dkankan-pay</artifactId>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alipay</groupId>
+            <artifactId>alipay-sdk-java</artifactId>
+            <version>20170324180803</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alipay</groupId>
+            <artifactId>alipay-trade-sdk</artifactId>
+            <version>20161215</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>core</artifactId>
+            <version>2.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-configuration</groupId>
+            <artifactId>commons-configuration</artifactId>
+            <version>1.10</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.paypal.sdk</groupId>
+            <artifactId>rest-api-sdk</artifactId>
+            <version>1.14.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-tx</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+    </dependencies>
+
+
+    <distributionManagement>
+        <repository>
+            <!-- 这里的ID要和setting的id一致 -->
+            <id>releases</id>
+            <url>http://192.168.0.115:8081/nexus-2.14.2-01/content/repositories/releases/</url>
+        </repository>
+        <!--这是打成快照版本的配置 -->
+        <snapshotRepository>
+            <id>snapshots</id>
+            <url>http://192.168.0.115:8081/nexus-2.14.2-01/content/repositories/snapshots/</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+        </plugins>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+            <resource>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*.xml</include>
+                </includes>
+            </resource>
+        </resources>
+    </build>
+</project>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 92 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/alipay/AlipayDefaultConfig.java


+ 81 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/alipay/sdk/AlipayConfig.java

@@ -0,0 +1,81 @@
+package com.fdkankan.pay.alipay.sdk;
+
+import com.alipay.demo.trade.service.AlipayTradeService;
+import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+public abstract class AlipayConfig {
+
+    /** 签名类型 */
+    private String signType = "RSA2";
+    /** 格式 */
+    private String formate = "json";
+    /** 编码 */
+    private String charset = "UTF-8";
+    /** 最大查询次数 */
+    private int maxQueryRetry = 5;
+    /** 查询间隔(毫秒) */
+    private long queryDuration = 5000;
+    /** 最大撤销次数 */
+    private int maxCancelRetry = 3;
+    /** 撤销间隔(毫秒) */
+    private long cancelDuration = 3000;
+
+    /** 支付宝gatewayUrl */
+    abstract public String getGatewayUrl();
+
+    /** 商户应用id */
+    abstract public String getAppid();
+
+    /** RSA私钥,用于对商户请求报文加签 */
+    abstract public String getAppPrivateKey();
+
+    /** 支付宝RSA公钥,用于验签支付宝应答 */
+    abstract public String getAlipayPublicKey();
+
+    /** 同步地址 */
+    abstract public String getReturnUrl();
+    /** 异步地址 */
+    abstract public String getNotifyUrl();
+
+    public String getSignType(){
+        return signType;
+    }
+
+    public String getFormate(){
+        return formate;
+    }
+
+    public String getCharset(){
+        return charset;
+    }
+
+    public int getMaxQueryRetry() {
+        return maxQueryRetry;
+    }
+
+    public long getQueryDuration() {
+        return queryDuration;
+    }
+
+    public int getMaxCancelRetry() {
+        return maxCancelRetry;
+    }
+
+    public long getCancelDuration() {
+        return cancelDuration;
+    }
+
+    @Bean
+    public AlipayTradeService alipayTradeService() {
+        return new AlipayTradeServiceImpl.ClientBuilder()
+                .setGatewayUrl(getGatewayUrl())
+                .setAppid(getAppid())
+                .setPrivateKey(getAppPrivateKey())
+                .setAlipayPublicKey(getAlipayPublicKey())
+                .setSignType(getSignType())
+                .build();
+    }
+}

+ 60 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/alipay/sdk/AlipayGoodsDetail.java

@@ -0,0 +1,60 @@
+package com.fdkankan.pay.alipay.sdk;
+
+import java.io.Serializable;
+
+public class AlipayGoodsDetail implements Serializable {
+
+    private static final long serialVersionUID = -8875896136641533825L;
+
+    public AlipayGoodsDetail() {
+    }
+
+    public static AlipayGoodsDetail newInstance(String goodsId, String goodsName, long price, int quantity) {
+        AlipayGoodsDetail info = new AlipayGoodsDetail();
+        info.setGoodsId(goodsId);
+        info.setGoodsName(goodsName);
+        info.setPrice(price);
+        info.setQuantity(quantity);
+        return info;
+    }
+    // 必填,商品的编号,length=32
+    private String goodsId;
+    // 必填,商品的名称,length=256
+    private String goodsName;
+    // 必填,商品数量
+    private int quantity;
+    // 必填,商品单价,单位为元
+    private long price;
+
+    public String getGoodsId() {
+        return goodsId;
+    }
+
+    public void setGoodsId(String goodsId) {
+        this.goodsId = goodsId;
+    }
+
+    public String getGoodsName() {
+        return goodsName;
+    }
+
+    public void setGoodsName(String goodsName) {
+        this.goodsName = goodsName;
+    }
+
+    public int getQuantity() {
+        return quantity;
+    }
+
+    public void setQuantity(int quantity) {
+        this.quantity = quantity;
+    }
+
+    public long getPrice() {
+        return price;
+    }
+
+    public void setPrice(long price) {
+        this.price = price;
+    }
+}

+ 161 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/alipay/sdk/AlipayService.java

@@ -0,0 +1,161 @@
+package com.fdkankan.pay.alipay.sdk;
+
+import com.alipay.api.AlipayApiException;
+import com.alipay.api.AlipayResponse;
+import com.alipay.api.domain.TradeFundBill;
+import com.alipay.api.response.AlipayTradePrecreateResponse;
+import com.alipay.api.response.AlipayTradeQueryResponse;
+import com.alipay.demo.trade.model.GoodsDetail;
+import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
+import com.alipay.demo.trade.model.builder.AlipayTradeQueryRequestBuilder;
+import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
+import com.alipay.demo.trade.model.result.AlipayF2FQueryResult;
+import com.alipay.demo.trade.service.AlipayTradeService;
+import com.alipay.demo.trade.utils.Utils;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class AlipayService {
+    private static Logger log = LoggerFactory.getLogger("programLog");
+
+    @Autowired
+    private AlipayTradeService alipayTradeService;
+
+    /**
+     * 当面付-扫码付
+     *
+     * 扫码支付,指用户打开支付宝钱包中的“扫一扫”功能,扫描商户针对每个订单实时生成的订单二维码,并在手机端确认支付。
+     *
+     * 发起预下单请求,同步返回订单二维码
+     *
+     * 适用场景:商家获取二维码展示在屏幕上,然后用户去扫描屏幕上的二维码
+     * @return
+     * @throws AlipayApiException
+     */
+    public Map<String, String> tradePrecreate(AlipaymentEx alipaymentEx, String notifyUrl) throws AlipayApiException {
+        if (StringUtils.isEmpty(alipaymentEx.getOutTradeNo())){
+            throw new AlipayApiException("outTradeNo should not be null");
+        }else if (StringUtils.isEmpty(alipaymentEx.getSubject())){
+            throw new AlipayApiException("subject should not be null");
+        }else if (StringUtils.isEmpty(alipaymentEx.getBody())){
+            throw new AlipayApiException("body should not be null");
+        }else if (alipaymentEx.getTotalAmount() == null){
+            throw new AlipayApiException("totalAmout should not be null");
+        }else if (StringUtils.isEmpty(alipaymentEx.getStoreId())){
+            throw new AlipayApiException("storeid should not be null");
+        }else if (alipaymentEx.getGoodsDetailList() == null || alipaymentEx.getGoodsDetailList().size() == 0){
+            throw new AlipayApiException("goodsDetailList should not be null");
+        }else if (StringUtils.isEmpty(notifyUrl)){
+            throw new AlipayApiException("notifyUrl should not be null");
+        }
+
+        List<AlipayGoodsDetail> alipayGoodsDetails = alipaymentEx.getGoodsDetailList();
+        List<GoodsDetail> goodsDetailList = new ArrayList<>();
+        for (AlipayGoodsDetail alipayGoodsDetail : alipayGoodsDetails){
+            GoodsDetail goods1 = GoodsDetail.newInstance(alipayGoodsDetail.getGoodsId(),
+                    alipayGoodsDetail.getGoodsName(), alipayGoodsDetail.getPrice(), alipayGoodsDetail.getQuantity());
+            goodsDetailList.add(goods1);
+        }
+
+        AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
+                .setSubject(alipaymentEx.getSubject())
+                .setTotalAmount(alipaymentEx.getTotalAmount().toString())
+                .setOutTradeNo(alipaymentEx.getOutTradeNo())
+                .setUndiscountableAmount(alipaymentEx.getUndiscountableAmount() == null ? "" : alipaymentEx.getUndiscountableAmount().toString())
+                .setSellerId(alipaymentEx.getSellerId() == null ? "" : alipaymentEx.getSellerId())
+                .setBody(alipaymentEx.getBody())
+                .setOperatorId(alipaymentEx.getOperatorId() == null ? "" : alipaymentEx.getOperatorId())
+                .setStoreId(alipaymentEx.getStoreId())
+                .setTimeoutExpress(alipaymentEx.getTimeoutExpress())
+                //支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
+                .setNotifyUrl(notifyUrl)
+                .setGoodsDetailList(goodsDetailList);
+
+        Map<String, String> resp = new HashMap<>();
+        AlipayF2FPrecreateResult result = alipayTradeService.tradePrecreate(builder);
+        AlipayTradePrecreateResponse res = result.getResponse();
+        switch (result.getTradeStatus()) {
+            case SUCCESS:
+                dumpResponse(res);
+                log.info("支付宝预下单成功。");
+                resp.put("code", "0");
+                resp.put("out_trade_no", res.getOutTradeNo());
+                resp.put("qr_code", res.getQrCode());
+                break;
+
+            case FAILED:
+                log.error("支付宝预下单失败,code:" + res.getCode() + ",msg:" + res.getMsg());
+                resp.put("code", "-1");
+                break;
+
+            case UNKNOWN:
+                log.error("系统异常,预下单状态未知,code:" + res.getCode() + ",msg:" + res.getMsg());
+                resp.put("code", "-2");
+                break;
+
+            default:
+                log.error("不支持的交易状态,交易返回异常,code:" + res.getCode() + ",msg:" + res.getMsg());
+                resp.put("code", "-3");
+                break;
+        }
+        return resp;
+    }
+
+    public String tradeQuery(String outTradeNo) {
+        // (必填) 商户订单号,通过此商户订单号查询当面付的交易状态
+        String Type;
+        // 创建查询请求builder,设置请求参数
+        AlipayTradeQueryRequestBuilder builder = new AlipayTradeQueryRequestBuilder()
+                .setOutTradeNo(outTradeNo);
+        System.out.println("请求参数:" + builder);
+        AlipayF2FQueryResult result = alipayTradeService.queryTradeResult(builder);
+        switch (result.getTradeStatus()) {
+            case SUCCESS:
+                log.info("查询返回该订单支付成功: )");
+                Type = "SUCCESS";
+                AlipayTradeQueryResponse response = result.getResponse();
+                dumpResponse(response);
+                log.info(response.getTradeStatus());
+                if (Utils.isListNotEmpty(response.getFundBillList())) {
+                    for (TradeFundBill bill : response.getFundBillList()) {
+                        log.info(bill.getFundChannel() + ":" + bill.getAmount());
+                    }
+                }
+                break;
+            case FAILED:
+                log.error("查询返回该订单支付失败或被关闭!!!");
+                Type = "FAILED";
+                break;
+            case UNKNOWN:
+                log.error("系统异常,订单支付状态未知!!!");
+                Type = "UNKNOWN";
+                break;
+            default:
+                log.error("不支持的交易状态,交易返回异常!!!");
+                Type = "default";
+                break;
+        }
+        return Type;
+    }
+
+    // 简单打印应答
+    private void dumpResponse(AlipayResponse response) {
+        if (response != null) {
+            log.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
+            if (StringUtils.isNotEmpty(response.getSubCode())) {
+                log.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
+                        response.getSubMsg()));
+            }
+            log.info("body:" + response.getBody());
+        }
+    }
+}

+ 38 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/alipay/sdk/AlipayUtil.java

@@ -0,0 +1,38 @@
+package com.fdkankan.pay.alipay.sdk;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.WriterException;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
+
+import java.awt.image.BufferedImage;
+import java.util.Hashtable;
+import java.util.Map;
+
+public class AlipayUtil {
+
+    /**
+     * 根据url生成二位图片对象
+     *
+     * @param codeUrl
+     * @return
+     * @throws WriterException
+     */
+    public static BufferedImage getQRCodeImge(String codeUrl) throws WriterException {
+        Map<EncodeHintType, Object> hints = new Hashtable();
+        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
+        hints.put(EncodeHintType.CHARACTER_SET, "UTF8");
+        int width = 300;
+        BitMatrix bitMatrix = (new MultiFormatWriter()).encode(codeUrl, BarcodeFormat.QR_CODE, width, width, hints);
+        BufferedImage image = new BufferedImage(width, width, 1);
+        for(int x = 0; x < width; ++x) {
+            for(int y = 0; y < width; ++y) {
+                image.setRGB(x, y, bitMatrix.get(x, y) ? -16777216 : -1);
+            }
+        }
+
+        return image;
+    }
+}

+ 113 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/alipay/sdk/AlipaymentEx.java

@@ -0,0 +1,113 @@
+package com.fdkankan.pay.alipay.sdk;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+public class AlipaymentEx implements Serializable {
+
+    private static final long serialVersionUID = 8082279987959002563L;
+    // (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、数字、下划线,
+    private String outTradeNo;
+    // (必填) 订单标题,粗略描述用户的支付目的。如“喜士多(浦东店)消费”
+    private String subject;
+    // 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元"
+    private String body;
+    // (必填) 订单总金额,单位为元,不能超过1亿元
+    // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
+    private BigDecimal totalAmount;
+    // (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段
+    // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
+    private BigDecimal undiscountableAmount;
+    // 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号)
+    // 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID
+    private String sellerId;
+    // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持
+    private String storeId;
+    // 商户操作员编号,添加此参数可以为商户操作员做销售统计
+    private String operatorId;
+    // 支付超时,线下扫码交易定义为5分钟
+    private String timeoutExpress = "5m";
+    // 商品明细列表,需填写购买商品详细信息
+    private List<AlipayGoodsDetail> goodsDetailList;
+
+    public String getOutTradeNo() {
+        return outTradeNo;
+    }
+
+    public void setOutTradeNo(String outTradeNo) {
+        this.outTradeNo = outTradeNo;
+    }
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public void setBody(String body) {
+        this.body = body;
+    }
+
+    public BigDecimal getTotalAmount() {
+        return totalAmount;
+    }
+
+    public void setTotalAmount(BigDecimal totalAmount) {
+        this.totalAmount = totalAmount;
+    }
+
+    public BigDecimal getUndiscountableAmount() {
+        return undiscountableAmount;
+    }
+
+    public void setUndiscountableAmount(BigDecimal undiscountableAmount) {
+        this.undiscountableAmount = undiscountableAmount;
+    }
+
+    public String getSellerId() {
+        return sellerId;
+    }
+
+    public void setSellerId(String sellerId) {
+        this.sellerId = sellerId;
+    }
+
+    public String getStoreId() {
+        return storeId;
+    }
+
+    public void setStoreId(String storeId) {
+        this.storeId = storeId;
+    }
+
+    public String getOperatorId() {
+        return operatorId;
+    }
+
+    public void setOperatorId(String operatorId) {
+        this.operatorId = operatorId;
+    }
+
+    public String getTimeoutExpress() {
+        return timeoutExpress;
+    }
+
+    public void setTimeoutExpress(String timeoutExpress) {
+        this.timeoutExpress = timeoutExpress;
+    }
+
+    public List<AlipayGoodsDetail> getGoodsDetailList() {
+        return goodsDetailList;
+    }
+
+    public void setGoodsDetailList(List<AlipayGoodsDetail> goodsDetailList) {
+        this.goodsDetailList = goodsDetailList;
+    }
+}

+ 56 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/PayPalDefaultConfig.java

@@ -0,0 +1,56 @@
+package com.fdkankan.pay.paypal;
+
+import com.fdkankan.pay.paypal.sdk.PayPalConfig;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PayPalDefaultConfig extends PayPalConfig {
+
+    @Override
+    public String getClientId() {
+        return "AZJEGWlvvI2q52bR4k_mC1ftW8tEnlaJj30huGQTBsdAjwmKlMDiEiMixVKbfrdw6fB55NSj_BAE8FPP";
+    }
+
+    @Override
+    public String getSecret() {
+        return "EL-RGNmsbFpcKT7QuIlxMxX7MQplp8rCyaGDZ5KOCMQ9BkOhY5OYZyVInAeHT8_4tXoPth8tOEZY_3s_";
+    }
+
+    @Override
+    public String getMode() {
+        return "live";
+    }
+
+    public String getPaySuccessUrl(){
+        return "api/order/pay/paypal/callback";
+    }
+
+    public String getH5PaySuccessUrl(){
+        return "api/order/pay/paypal/callbackH5";
+    }
+
+    public String getCancelUrl(){
+        return "api/order/pay/paypal/cancel";
+    }
+
+    public String getH5CancelUrl(){
+        return "api/order/pay/paypal/cancelH5";
+    }
+
+    public String getSuccessUrl(){
+        return "index.html#/payresult/success/recharge";
+    }
+
+    public String getFailUrl(){
+        return "#/payresult/fail/recharge";
+    }
+
+    public String getH5SuccessUrl(){
+        return "mobile.html#/payresult/success";
+    }
+
+    public String getH5FailUrl(){
+        return "mobile.html#/payresult/fail";
+    }
+
+}

+ 43 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PayPalConfig.java

@@ -0,0 +1,43 @@
+package com.fdkankan.pay.paypal.sdk;
+
+import com.paypal.base.rest.APIContext;
+import com.paypal.base.rest.OAuthTokenCredential;
+import com.paypal.base.rest.PayPalRESTException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@Component
+public abstract class PayPalConfig {
+
+    abstract public String getClientId();
+
+    abstract public String getSecret();
+
+    abstract public String getMode();
+
+    @Bean
+    public Map<String, String> paypalSdkConfig(){
+        Map<String, String> sdkConfig = new HashMap<>();
+        sdkConfig.put("mode", getMode());
+        return sdkConfig;
+    }
+
+    @Bean
+    public OAuthTokenCredential authTokenCredential(){
+        return new OAuthTokenCredential(getClientId(), getSecret(), paypalSdkConfig());
+    }
+
+    @Bean
+    public APIContext apiContext() throws PayPalRESTException {
+        String accessToken = authTokenCredential().getAccessToken();
+        log.info("paypal新的accessToken:" + accessToken);
+        APIContext apiContext = new APIContext(accessToken);
+        apiContext.setConfigurationMap(paypalSdkConfig());
+        return apiContext;
+    }
+}

+ 130 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PayPalmentEx.java

@@ -0,0 +1,130 @@
+package com.fdkankan.pay.paypal.sdk;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+public class PayPalmentEx implements Serializable {
+
+    private static final long serialVersionUID = 5027458587257867876L;
+    /**
+     * 订单Id
+     */
+    private String orderSn;
+    /**
+     * 支付的总价
+     */
+    private BigDecimal orderTotal;
+    /**
+     * 商品总价
+     */
+    private BigDecimal subTotal;
+    /**
+     * 税费
+     */
+    private BigDecimal tax;
+    /**
+     * 描述
+     */
+    private String description;
+    /**
+     * 成功回调url
+     */
+    private String successUrl;
+    /**
+     * 支付失败url
+     */
+    private String failUrl;
+    /**
+     * 取消支付url
+     */
+    private String cancelUrl;
+    /**
+     * 收货地址
+     */
+    private PaypalOrderAddressEx paypayOrderAddressEx;
+    /**
+     * 订单商品明细
+     */
+    private List<PaypalOrderItemEx> paypalOrderItemExList;
+
+    public String getOrderSn() {
+        return orderSn;
+    }
+
+    public void setOrderSn(String orderSn) {
+        this.orderSn = orderSn;
+    }
+
+    public BigDecimal getOrderTotal() {
+        return orderTotal;
+    }
+
+    public void setOrderTotal(BigDecimal orderTotal) {
+        this.orderTotal = orderTotal;
+    }
+
+    public BigDecimal getSubTotal() {
+        return subTotal;
+    }
+
+    public void setSubTotal(BigDecimal subTotal) {
+        this.subTotal = subTotal;
+    }
+
+    public BigDecimal getTax() {
+        return tax;
+    }
+
+    public void setTax(BigDecimal tax) {
+        this.tax = tax;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getSuccessUrl() {
+        return successUrl;
+    }
+
+    public void setSuccessUrl(String successUrl) {
+        this.successUrl = successUrl;
+    }
+
+    public String getFailUrl() {
+        return failUrl;
+    }
+
+    public void setFailUrl(String failUrl) {
+        this.failUrl = failUrl;
+    }
+
+    public String getCancelUrl() {
+        return cancelUrl;
+    }
+
+    public void setCancelUrl(String cancelUrl) {
+        this.cancelUrl = cancelUrl;
+    }
+
+    public PaypalOrderAddressEx getPaypayOrderAddressEx() {
+        return paypayOrderAddressEx;
+    }
+
+    public void setPaypayOrderAddressEx(PaypalOrderAddressEx paypayOrderAddressEx) {
+        this.paypayOrderAddressEx = paypayOrderAddressEx;
+    }
+
+    public List<PaypalOrderItemEx> getPaypalOrderItemExList() {
+        return paypalOrderItemExList;
+    }
+
+    public void setPaypalOrderItemExList(List<PaypalOrderItemEx> paypalOrderItemExList) {
+        this.paypalOrderItemExList = paypalOrderItemExList;
+    }
+}

+ 88 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PaypalOrderAddressEx.java

@@ -0,0 +1,88 @@
+package com.fdkankan.pay.paypal.sdk;
+
+import java.io.Serializable;
+
+public class PaypalOrderAddressEx implements Serializable {
+
+    private static final long serialVersionUID = 5667747195118555705L;
+
+    private String firstName;
+
+    private String lastName;
+
+    private String countryCode;
+
+    private String state;
+
+    private String city;
+
+    private String address;
+
+    private String phone;
+
+    private String postalCode;
+
+    public String getFirstName() {
+        return firstName;
+    }
+
+    public void setFirstName(String firstName) {
+        this.firstName = firstName;
+    }
+
+    public String getLastName() {
+        return lastName;
+    }
+
+    public void setLastName(String lastName) {
+        this.lastName = lastName;
+    }
+
+    public String getCountryCode() {
+        return countryCode;
+    }
+
+    public void setCountryCode(String countryCode) {
+        this.countryCode = countryCode;
+    }
+
+    public String getState() {
+        return state;
+    }
+
+    public void setState(String state) {
+        this.state = state;
+    }
+
+    public String getCity() {
+        return city;
+    }
+
+    public void setCity(String city) {
+        this.city = city;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+    public String getPostalCode() {
+        return postalCode;
+    }
+
+    public void setPostalCode(String postalCode) {
+        this.postalCode = postalCode;
+    }
+}

+ 59 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PaypalOrderItemEx.java

@@ -0,0 +1,59 @@
+package com.fdkankan.pay.paypal.sdk;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+public class PaypalOrderItemEx implements Serializable {
+
+    private static final long serialVersionUID = 7764234386178614511L;
+
+    private String sku;
+
+    private String name;
+
+    private BigDecimal price;
+
+    private int quantity;
+
+    private String currency;
+
+    public String getSku() {
+        return sku;
+    }
+
+    public void setSku(String sku) {
+        this.sku = sku;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public BigDecimal getPrice() {
+        return price;
+    }
+
+    public void setPrice(BigDecimal price) {
+        this.price = price;
+    }
+
+    public int getQuantity() {
+        return quantity;
+    }
+
+    public void setQuantity(int quantity) {
+        this.quantity = quantity;
+    }
+
+    public String getCurrency() {
+        return currency;
+    }
+
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+}

+ 5 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PaypalPaymentIntent.java

@@ -0,0 +1,5 @@
+package com.fdkankan.pay.paypal.sdk;
+
+public enum PaypalPaymentIntent {
+	sale, authorize, order
+}

+ 5 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PaypalPaymentMethod.java

@@ -0,0 +1,5 @@
+package com.fdkankan.pay.paypal.sdk;
+
+public enum PaypalPaymentMethod {
+	credit_card, paypal
+}

+ 268 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/PaypalService.java

@@ -0,0 +1,268 @@
+package com.fdkankan.pay.paypal.sdk;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.fdkankan.pay.paypal.PayPalDefaultConfig;
+import com.paypal.api.payments.*;
+import com.paypal.base.codec.binary.Base64;
+import com.paypal.base.rest.APIContext;
+import com.paypal.base.rest.PayPalRESTException;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class PaypalService {
+    private static Logger log = LoggerFactory.getLogger("programLog");
+
+    @Autowired
+    private APIContext apiContext;
+    @Autowired
+    private PayPalDefaultConfig config;
+
+    private static final String CURRENCY = "USD";
+
+    /**
+     * 创建支付
+     *
+     * @param paymentEx
+     * @return
+     * @throws PayPalRESTException
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public Payment createPayment(PayPalmentEx paymentEx, String successUrl, String cancelUrl) throws PayPalRESTException {
+        if (StringUtils.isEmpty(successUrl) || StringUtils.isEmpty(cancelUrl)) {
+            throw new PayPalRESTException("缺少url");
+        }
+        Transaction transaction = new Transaction();
+        transaction.setDescription(paymentEx.getDescription());
+        // 将我们的订单ID保存到支付信息中,用于后面支付回传
+        if (null != paymentEx.getOrderSn()) {
+            transaction.setCustom(paymentEx.getOrderSn());
+        }
+        //订单价格
+        Amount amount = new Amount();
+        amount.setCurrency(CURRENCY);
+        // 支付的总价,paypal会校验 total = subTotal + tax + ...
+        amount.setTotal(paymentEx.getOrderTotal().toString());
+        // 设置各种费用
+        Details details = new Details();
+        // 商品总价
+        if (paymentEx.getSubTotal() != null) {
+            details.setSubtotal(paymentEx.getSubTotal().toString());
+        }
+        // 税费
+        if (paymentEx.getTax() != null) {
+            details.setTax(paymentEx.getTax().toString());
+        }
+
+        amount.setDetails(details);
+
+        transaction.setAmount(amount);
+
+        ItemList itemList = new ItemList();
+        // 收货地址
+        PaypalOrderAddressEx orderAddress = paymentEx.getPaypayOrderAddressEx();
+        if (orderAddress != null) {
+            ShippingAddress shippingAddress = new ShippingAddress();
+            if (StringUtils.isNotEmpty(orderAddress.getFirstName()) && StringUtils.isNotEmpty(orderAddress.getLastName())) {
+                shippingAddress.setRecipientName(orderAddress.getFirstName() + "." + orderAddress.getLastName());
+            }
+            shippingAddress.setCountryCode(orderAddress.getCountryCode());
+            shippingAddress.setState(orderAddress.getState());
+            shippingAddress.setCity(orderAddress.getCity());
+            shippingAddress.setLine1(orderAddress.getAddress());
+            shippingAddress.setPhone(orderAddress.getPhone());
+            shippingAddress.setPostalCode(orderAddress.getPostalCode());
+
+            itemList.setShippingAddress(shippingAddress);
+            itemList.setShippingPhoneNumber(orderAddress.getPhone());
+        }
+
+        // 商品明细
+        List<PaypalOrderItemEx> orderItemList = paymentEx.getPaypalOrderItemExList();
+        if (orderItemList != null && orderItemList.size() > 0) {
+            List<Item> items = new ArrayList<>();
+            for (PaypalOrderItemEx orderItemEx : orderItemList) {
+                Item item = new Item();
+                item.setSku(orderItemEx.getSku());
+                item.setName(orderItemEx.getName());
+                item.setPrice(orderItemEx.getPrice().toString());
+                item.setQuantity(String.valueOf(orderItemEx.getQuantity()));
+                item.setCurrency(CURRENCY);
+                items.add(item);
+            }
+            itemList.setItems(items);
+            transaction.setItemList(itemList);
+        }
+
+        List<Transaction> transactions = new ArrayList<>();
+        transactions.add(transaction);
+
+        // 支付信息
+        Payer payer = new Payer();
+        payer.setPaymentMethod(PaypalPaymentMethod.paypal.toString());
+
+        Payment payment = new Payment();
+        //刷新accessToken时间;
+        apiContext = new APIContext("Bearer " + getAccessToken());
+        apiContext.setConfigurationMap(config.paypalSdkConfig());
+
+        payment.setIntent(PaypalPaymentIntent.sale.toString());
+        payment.setPayer(payer);
+        payment.setTransactions(transactions);
+
+        //回调地址
+        RedirectUrls redirectUrls = new RedirectUrls();
+        redirectUrls.setReturnUrl(successUrl);
+        redirectUrls.setCancelUrl(cancelUrl);
+        payment.setRedirectUrls(redirectUrls);
+
+        return payment.create(apiContext);
+    }
+
+    /**
+     * 执行支付
+     *
+     * @param paymentId
+     * @param payerId
+     * @return
+     * @throws PayPalRESTException
+     */
+    public Payment executePayment(String paymentId, String payerId) throws PayPalRESTException {
+        Payment payment = new Payment();
+        payment.setId(paymentId);
+        PaymentExecution paymentExecute = new PaymentExecution();
+        paymentExecute.setPayerId(payerId);
+        apiContext = new APIContext("Bearer " + getAccessToken());
+        apiContext.setConfigurationMap(config.paypalSdkConfig());
+        return payment.execute(apiContext, paymentExecute);
+    }
+
+    /**
+      * 获取token
+      * 了解更多:https://developer.paypal.com/webapps/developer/docs/integration/mobile/verify-mobile-payment/
+      * @return
+      */
+    private String getAccessToken() {
+        BufferedReader reader = null;
+        try {
+            URL url = new URL(UrlUtils.TOKEN_URL);
+            String authorization = config.getClientId() + ":" + config.getSecret();
+            authorization = Base64.encodeBase64String(authorization.getBytes());
+
+            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            conn.setRequestMethod("POST");// 提交模式
+            //设置请求头header
+            conn.setRequestProperty("Accept", "application/json");
+            conn.setRequestProperty("Accept-Language", "en_US");
+            conn.setRequestProperty("Authorization", "Basic " + authorization);
+            // conn.setConnectTimeout(10000);//连接超时 单位毫秒
+            // conn.setReadTimeout(2000);//读取超时 单位毫秒
+            conn.setDoOutput(true);// 是否输入参数
+            String params = "grant_type=client_credentials";
+            conn.getOutputStream().write(params.getBytes());// 输入参数
+
+            InputStreamReader inStream = new InputStreamReader(conn.getInputStream());
+            reader = new BufferedReader(inStream);
+            StringBuilder result = new StringBuilder();
+            String lineTxt = null;
+            while ((lineTxt = reader.readLine()) != null) {
+                result.append(lineTxt);
+            }
+            reader.close();
+            String accessTokey = JSONObject.parseObject(result.toString()).getString("access_token");
+            log.info("getAccessToken:" + accessTokey);
+            return accessTokey;
+        } catch (Exception err) {
+            err.printStackTrace();
+        } finally {
+            if (reader != null){
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return null;
+    }
+
+    public String getPaymentDetails(String paymentId) {
+        BufferedReader reader = null;
+        try {
+            URL url = new URL(UrlUtils.PAYMENT_DETAIL + paymentId);
+            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            conn.setRequestMethod("GET");// 提交模式
+            //设置请求头header
+            conn.setRequestProperty("Accept", "application/json");
+            conn.setRequestProperty("Authorization", "Bearer " + getAccessToken());
+            // conn.setConnectTimeout(10000);//连接超时 单位毫秒
+            // conn.setReadTimeout(2000);//读取超时 单位毫秒
+            InputStreamReader inStream = new InputStreamReader(conn.getInputStream());
+            reader = new BufferedReader(inStream);
+            StringBuilder result = new StringBuilder();
+            String lineTxt = null;
+            while ((lineTxt = reader.readLine()) != null) {
+                result.append(lineTxt);
+            }
+            reader.close();
+            return result.toString();
+        } catch (Exception err) {
+            err.printStackTrace();
+        }finally {
+            if (reader != null){
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return null;
+    }
+
+    public boolean verifyPayment(String paymentId){
+        //从PayPal获取付款详情
+        String str = getPaymentDetails(paymentId);
+        JSONObject detail = JSONObject.parseObject(str);
+        //校验订单是否完成
+        if("approved".equals(detail.getString("state"))){
+            JSONObject transactions = detail.getJSONArray("transactions").getJSONObject(0);
+            JSONObject amount = transactions.getJSONObject("amount");
+            JSONArray relatedResources = transactions.getJSONArray("related_resources");
+            //从数据库查询总金额与Paypal校验支付总金额
+            double total = 0;
+            if( total != amount.getDouble("total") ){
+                return false;
+            }
+            //校验交易货币类型
+            String currency = "USD";
+            if( !currency.equals(amount.getString("currency")) ){
+                return false;
+            }
+            //校验每个子订单是否完成
+            for (int i = 0,j = relatedResources.size(); i < j; i++) {
+                JSONObject sale = relatedResources.getJSONObject(i).getJSONObject("sale");
+                if( !"completed".equals(sale.getString("state")) ){
+                    System.out.println("子订单未完成,订单状态:"+sale.getString("state"));
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+
+}

+ 66 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/paypal/sdk/UrlUtils.java

@@ -0,0 +1,66 @@
+package com.fdkankan.pay.paypal.sdk;
+
+import javax.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+public class UrlUtils {
+
+    //沙箱链接
+//    public static final String TOKEN_URL = "https://api.sandbox.paypal.com/v1/oauth2/token";
+    public static final String TOKEN_URL = "https://api.paypal.com/v1/oauth2/token";
+    public static final String PAYMENT_DETAIL = "https://api.sandbox.paypal.com/v1/payments/payment/";
+
+    public static String getBaseURl(HttpServletRequest request) {
+        String scheme = request.getScheme();
+        String serverName = request.getServerName();
+        int serverPort = request.getServerPort();
+        String contextPath = request.getContextPath();
+        StringBuffer url =  new StringBuffer();
+        url.append(scheme).append("://").append(serverName);
+        if ((serverPort != 80) && (serverPort != 443)) {
+            url.append(":").append(serverPort);
+        }
+        url.append(contextPath);
+        if(url.toString().endsWith("/")){
+            url.append("/");
+        }
+        return url.toString();
+    }
+
+    /**
+     * 获取用户实际ip
+     * @param request
+     * @return
+     */
+    public static String getIpAddr(HttpServletRequest request){
+        String ipAddress = request.getHeader("x-forwarded-for");
+        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+            ipAddress = request.getHeader("Proxy-Client-IP");
+        }
+        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+            ipAddress = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+            ipAddress = request.getRemoteAddr();
+            if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){
+                //根据网卡取本机配置的IP
+                InetAddress inet=null;
+                try {
+                    inet = InetAddress.getLocalHost();
+                } catch (UnknownHostException e) {
+                    e.printStackTrace();
+                }
+                ipAddress= inet.getHostAddress();
+            }
+        }
+        //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
+        if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15
+            if(ipAddress.indexOf(",")>0){
+                ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));
+            }
+        }
+        return ipAddress;
+    }
+
+}

+ 64 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/wx/WXPayDefaultConfig.java

@@ -0,0 +1,64 @@
+package com.fdkankan.pay.wx;
+
+import com.fdkankan.pay.wx.sdk.WXPayConfig;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+public class WXPayDefaultConfig implements WXPayConfig {
+
+    private byte[] certData;
+
+    public WXPayDefaultConfig() throws Exception {
+        /*String certPath = CONSTANTFILEPATH.WEIXINCERT;
+        File file = new File(certPath);
+        InputStream certStream = new FileInputStream(file);
+        this.certData = new byte[(int) file.length()];
+        certStream.read(this.certData);
+        certStream.close();*/
+    }
+
+    public String getAppID() {
+        return "wx779dbafb46bab697";
+    }
+
+    public String getMchID() {
+        return "1505605401";
+    }
+
+    public String getKey() {
+        return "4DAGE1684DAGE1684DAGE1684DAGE168";
+    }
+
+    public String getSecret() {
+        return "b578c41b560f37c2c2c1981114830d23";
+    }
+
+    public String getCreateIP() {
+        return "47.104.99.106";
+    }
+
+    public String getH5RedirectURL() {
+        return "mobile.html#/check";
+    }
+
+    public String getNotifyURL() {
+        return "api/order/pay/wechatPay/notify";
+    }
+
+    public String getOrderURL() {
+        return "https://api.mch.weixin.qq.com/pay/unifiedorder";
+    }
+
+    public InputStream getCertStream() {
+        return new ByteArrayInputStream(this.certData);
+    }
+
+    public int getHttpConnectTimeoutMs() {
+        return 8000;
+    }
+
+    public int getHttpReadTimeoutMs() {
+        return 10000;
+    }
+}

+ 673 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/wx/sdk/WXPay.java

@@ -0,0 +1,673 @@
+package com.fdkankan.pay.wx.sdk;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+public class WXPay {
+
+    private WXPayConfig config;
+    private WXPayConstants.SignType signType;
+    private boolean useSandbox;
+
+    public WXPay(final WXPayConfig config) {
+        this(config, WXPayConstants.SignType.MD5, false);
+    }
+
+    public WXPay(final WXPayConfig config, final WXPayConstants.SignType signType) {
+        this(config, signType, false);
+    }
+
+    public WXPay(final WXPayConfig config, final WXPayConstants.SignType signType, final boolean useSandbox) {
+        this.config = config;
+        this.signType = signType;
+        this.useSandbox = useSandbox;
+    }
+
+
+    /**
+     * 向 Map 中添加 appid、mch_id、nonce_str、sign_type、sign <br>
+     * 该函数适用于商户适用于统一下单等接口,不适用于红包、代金券接口
+     *
+     * @param reqData
+     * @return
+     * @throws Exception
+     */
+    public Map<String, String> fillRequestData(Map<String, String> reqData) throws Exception {
+        reqData.put("appid", config.getAppID());
+        reqData.put("mch_id", config.getMchID());
+        reqData.put("nonce_str", WXPayUtil.generateNonceStr());
+        if (WXPayConstants.SignType.MD5.equals(this.signType)) {
+            reqData.put("sign_type", WXPayConstants.MD5);
+        }
+        else if (WXPayConstants.SignType.HMACSHA256.equals(this.signType)) {
+            reqData.put("sign_type", WXPayConstants.HMACSHA256);
+        }
+        reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType));
+        return reqData;
+    }
+
+    /**
+     * 判断xml数据的sign是否有效,必须包含sign字段,否则返回false。
+     *
+     * @param reqData 向wxpay post的请求数据
+     * @return 签名是否有效
+     * @throws Exception
+     */
+    public boolean isResponseSignatureValid(Map<String, String> reqData) throws Exception {
+        // 返回数据的签名方式和请求中给定的签名方式是一致的
+        return WXPayUtil.isSignatureValid(reqData, this.config.getKey(), this.signType);
+    }
+
+    /**
+     * 判断支付结果通知中的sign是否有效
+     *
+     * @param reqData 向wxpay post的请求数据
+     * @return 签名是否有效
+     * @throws Exception
+     */
+    public boolean isPayResultNotifySignatureValid(Map<String, String> reqData) throws Exception {
+        String signTypeInData = reqData.get(WXPayConstants.FIELD_SIGN_TYPE);
+        WXPayConstants.SignType signType;
+        if (signTypeInData == null) {
+            signType = WXPayConstants.SignType.MD5;
+        }
+        else {
+            signTypeInData = signTypeInData.trim();
+            if (signTypeInData.length() == 0) {
+                signType = WXPayConstants.SignType.MD5;
+            }
+            else if (WXPayConstants.MD5.equals(signTypeInData)) {
+                signType = WXPayConstants.SignType.MD5;
+            }
+            else if (WXPayConstants.HMACSHA256.equals(signTypeInData)) {
+                signType = WXPayConstants.SignType.HMACSHA256;
+            }
+            else {
+                throw new Exception(String.format("Unsupported sign_type: %s", signTypeInData));
+            }
+        }
+        return WXPayUtil.isSignatureValid(reqData, this.config.getKey(), signType);
+    }
+
+
+    /**
+     * 不需要证书的请求
+     * @param strUrl String
+     * @param reqData 向wxpay post的请求数据
+     * @param connectTimeoutMs 超时时间,单位是毫秒
+     * @param readTimeoutMs 超时时间,单位是毫秒
+     * @return API返回数据
+     * @throws Exception
+     */
+    public String requestWithoutCert(String strUrl, Map<String, String> reqData,
+                                     int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String UTF8 = "UTF-8";
+        String reqBody = WXPayUtil.mapToXml(reqData);
+        URL httpUrl = new URL(strUrl);
+        HttpURLConnection httpURLConnection = (HttpURLConnection) httpUrl.openConnection();
+        httpURLConnection.setDoOutput(true);
+        httpURLConnection.setRequestMethod("POST");
+        httpURLConnection.setConnectTimeout(connectTimeoutMs);
+        httpURLConnection.setReadTimeout(readTimeoutMs);
+        httpURLConnection.connect();
+        OutputStream outputStream = httpURLConnection.getOutputStream();
+        outputStream.write(reqBody.getBytes(UTF8));
+
+        // if (httpURLConnection.getResponseCode()!= 200) {
+        //     throw new Exception(String.format("HTTP response code is %d, not 200", httpURLConnection.getResponseCode()));
+        // }
+
+        //获取内容
+        InputStream inputStream = httpURLConnection.getInputStream();
+        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, UTF8));
+        final StringBuffer stringBuffer = new StringBuffer();
+        String line = null;
+        while ((line = bufferedReader.readLine()) != null) {
+            stringBuffer.append(line).append("\n");
+        }
+        String resp = stringBuffer.toString();
+        if (stringBuffer!=null) {
+            try {
+                bufferedReader.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        if (inputStream!=null) {
+            try {
+                inputStream.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        if (outputStream!=null) {
+            try {
+                outputStream.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        // if (httpURLConnection!=null) {
+        //     httpURLConnection.disconnect();
+        // }
+
+        return resp;
+    }
+
+
+    /**
+     * 需要证书的请求
+     * @param strUrl String
+     * @param reqData 向wxpay post的请求数据  Map
+     * @param connectTimeoutMs 超时时间,单位是毫秒
+     * @param readTimeoutMs 超时时间,单位是毫秒
+     * @return API返回数据
+     * @throws Exception
+     */
+    public String requestWithCert(String strUrl, Map<String, String> reqData,
+                                  int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String UTF8 = "UTF-8";
+        String reqBody = WXPayUtil.mapToXml(reqData);
+        URL httpUrl = new URL(strUrl);
+        char[] password = config.getMchID().toCharArray();
+        InputStream certStream = config.getCertStream();
+        KeyStore ks = KeyStore.getInstance("PKCS12");
+        ks.load(certStream, password);
+
+        // 实例化密钥库 & 初始化密钥工厂
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+        kmf.init(ks, password);
+
+        // 创建SSLContext
+        SSLContext sslContext = SSLContext.getInstance("TLS");
+        sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
+        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
+
+        HttpURLConnection httpURLConnection = (HttpURLConnection) httpUrl.openConnection();
+
+        httpURLConnection.setDoOutput(true);
+        httpURLConnection.setRequestMethod("POST");
+        httpURLConnection.setConnectTimeout(connectTimeoutMs);
+        httpURLConnection.setReadTimeout(readTimeoutMs);
+        httpURLConnection.connect();
+        OutputStream outputStream = httpURLConnection.getOutputStream();
+        outputStream.write(reqBody.getBytes(UTF8));
+
+        // if (httpURLConnection.getResponseCode()!= 200) {
+        //     throw new Exception(String.format("HTTP response code is %d, not 200", httpURLConnection.getResponseCode()));
+        // }
+
+        //获取内容
+        InputStream inputStream = httpURLConnection.getInputStream();
+        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, UTF8));
+        final StringBuffer stringBuffer = new StringBuffer();
+        String line = null;
+        while ((line = bufferedReader.readLine()) != null) {
+            stringBuffer.append(line);
+        }
+        String resp = stringBuffer.toString();
+        if (stringBuffer!=null) {
+            try {
+                bufferedReader.close();
+            } catch (IOException e) {
+                // e.printStackTrace();
+            }
+        }
+        if (inputStream!=null) {
+            try {
+                inputStream.close();
+            } catch (IOException e) {
+                // e.printStackTrace();
+            }
+        }
+        if (outputStream!=null) {
+            try {
+                outputStream.close();
+            } catch (IOException e) {
+                // e.printStackTrace();
+            }
+        }
+        if (certStream!=null) {
+            try {
+                certStream.close();
+            } catch (IOException e) {
+                // e.printStackTrace();
+            }
+        }
+        // if (httpURLConnection!=null) {
+        //     httpURLConnection.disconnect();
+        // }
+
+        return resp;
+    }
+
+    /**
+     * 处理 HTTPS API返回数据,转换成Map对象。return_code为SUCCESS时,验证签名。
+     * @param xmlStr API返回的XML格式数据
+     * @return Map类型数据
+     * @throws Exception
+     */
+    public Map<String, String> processResponseXml(String xmlStr) throws Exception {
+        String RETURN_CODE = "return_code";
+        String return_code;
+        Map<String, String> respData = WXPayUtil.xmlToMap(xmlStr);
+        if (respData.containsKey(RETURN_CODE)) {
+            return_code = respData.get(RETURN_CODE);
+        }
+        else {
+            throw new Exception(String.format("No `return_code` in XML: %s", xmlStr));
+        }
+
+        if (return_code.equals(WXPayConstants.FAIL)) {
+            return respData;
+        }
+        else if (return_code.equals(WXPayConstants.SUCCESS)) {
+           if (this.isResponseSignatureValid(respData)) {
+               return respData;
+           }
+           else {
+               throw new Exception(String.format("Invalid sign value in XML: %s", xmlStr));
+           }
+        }
+        else {
+            throw new Exception(String.format("return_code value %s is invalid in XML: %s", return_code, xmlStr));
+        }
+    }
+
+    /**
+     * 作用:提交刷卡支付<br>
+     * 场景:刷卡支付
+     * @param reqData 向wxpay post的请求数据
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> microPay(Map<String, String> reqData) throws Exception {
+        return this.microPay(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+    }
+
+
+    /**
+     * 作用:提交刷卡支付<br>
+     * 场景:刷卡支付
+     * @param reqData 向wxpay post的请求数据
+     * @param connectTimeoutMs 连接超时时间,单位是毫秒
+     * @param readTimeoutMs 读超时时间,单位是毫秒
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> microPay(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String url;
+        if (this.useSandbox) {
+            url = WXPayConstants.SANDBOX_MICROPAY_URL;
+        }
+        else {
+            url = WXPayConstants.MICROPAY_URL;
+        }
+        String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+        return this.processResponseXml(respXml);
+    }
+
+
+    /**
+     * 作用:统一下单<br>
+     * 场景:公共号支付、扫码支付、APP支付
+     * @param reqData 向wxpay post的请求数据
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> unifiedOrder(Map<String, String> reqData) throws Exception {
+        return this.unifiedOrder(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+    }
+
+
+    /**
+     * 作用:统一下单<br>
+     * 场景:公共号支付、扫码支付、APP支付
+     * @param reqData 向wxpay post的请求数据
+     * @param connectTimeoutMs 连接超时时间,单位是毫秒
+     * @param readTimeoutMs 读超时时间,单位是毫秒
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> unifiedOrder(Map<String, String> reqData,  int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String url;
+        if (this.useSandbox) {
+            url = WXPayConstants.SANDBOX_UNIFIEDORDER_URL;
+        }
+        else {
+            url = WXPayConstants.UNIFIEDORDER_URL;
+        }
+        String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+        return this.processResponseXml(respXml);
+    }
+
+
+    /**
+     * 作用:查询订单<br>
+     * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+     * @param reqData 向wxpay post的请求数据
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> orderQuery(Map<String, String> reqData) throws Exception {
+        return this.orderQuery(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+    }
+
+
+    /**
+     * 作用:查询订单<br>
+     * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+     * @param reqData 向wxpay post的请求数据 int
+     * @param connectTimeoutMs 连接超时时间,单位是毫秒
+     * @param readTimeoutMs 读超时时间,单位是毫秒
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> orderQuery(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String url;
+        if (this.useSandbox) {
+            url = WXPayConstants.SANDBOX_ORDERQUERY_URL;
+        }
+        else {
+            url = WXPayConstants.ORDERQUERY_URL;
+        }
+        String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+        return this.processResponseXml(respXml);
+    }
+
+
+    /**
+     * 作用:撤销订单<br>
+     * 场景:刷卡支付
+     * @param reqData 向wxpay post的请求数据
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> reverse(Map<String, String> reqData) throws Exception {
+        return this.reverse(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+    }
+
+
+    /**
+     * 作用:撤销订单<br>
+     * 场景:刷卡支付<br>
+     * 其他:需要证书
+     * @param reqData 向wxpay post的请求数据
+     * @param connectTimeoutMs 连接超时时间,单位是毫秒
+     * @param readTimeoutMs 读超时时间,单位是毫秒
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> reverse(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String url;
+        if (this.useSandbox) {
+            url = WXPayConstants.SANDBOX_REVERSE_URL;
+        }
+        else {
+            url = WXPayConstants.REVERSE_URL;
+        }
+        String respXml = this.requestWithCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+        return this.processResponseXml(respXml);
+    }
+
+
+    /**
+     * 作用:关闭订单<br>
+     * 场景:公共号支付、扫码支付、APP支付
+     * @param reqData 向wxpay post的请求数据
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> closeOrder(Map<String, String> reqData) throws Exception {
+        return this.closeOrder(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+    }
+
+
+    /**
+     * 作用:关闭订单<br>
+     * 场景:公共号支付、扫码支付、APP支付
+     * @param reqData 向wxpay post的请求数据
+     * @param connectTimeoutMs 连接超时时间,单位是毫秒
+     * @param readTimeoutMs 读超时时间,单位是毫秒
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> closeOrder(Map<String, String> reqData,  int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String url;
+        if (this.useSandbox) {
+            url = WXPayConstants.SANDBOX_CLOSEORDER_URL;
+        }
+        else {
+            url = WXPayConstants.CLOSEORDER_URL;
+        }
+        String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+        return this.processResponseXml(respXml);
+    }
+
+
+    /**
+     * 作用:申请退款<br>
+     * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+     * @param reqData 向wxpay post的请求数据
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> refund(Map<String, String> reqData) throws Exception {
+        return this.refund(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+    }
+
+
+    /**
+     * 作用:申请退款<br>
+     * 场景:刷卡支付、公共号支付、扫码支付、APP支付<br>
+     * 其他:需要证书
+     * @param reqData 向wxpay post的请求数据
+     * @param connectTimeoutMs 连接超时时间,单位是毫秒
+     * @param readTimeoutMs 读超时时间,单位是毫秒
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> refund(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String url;
+        if (this.useSandbox) {
+            url = WXPayConstants.SANDBOX_REFUND_URL;
+        }
+        else {
+            url = WXPayConstants.REFUND_URL;
+        }
+        String respXml = this.requestWithCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+        return this.processResponseXml(respXml);
+    }
+
+
+    /**
+     * 作用:退款查询<br>
+     * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+     * @param reqData 向wxpay post的请求数据
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> refundQuery(Map<String, String> reqData) throws Exception {
+        return this.refundQuery(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+    }
+
+
+    /**
+     * 作用:退款查询<br>
+     * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+     * @param reqData 向wxpay post的请求数据
+     * @param connectTimeoutMs 连接超时时间,单位是毫秒
+     * @param readTimeoutMs 读超时时间,单位是毫秒
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> refundQuery(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String url;
+        if (this.useSandbox) {
+            url = WXPayConstants.SANDBOX_REFUNDQUERY_URL;
+        }
+        else {
+            url = WXPayConstants.REFUNDQUERY_URL;
+        }
+        String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+        return this.processResponseXml(respXml);
+    }
+
+
+    /**
+     * 作用:对账单下载(成功时返回对账单数据,失败时返回XML格式数据)<br>
+     * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+     * @param reqData 向wxpay post的请求数据
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> downloadBill(Map<String, String> reqData) throws Exception {
+        return this.downloadBill(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+    }
+
+
+    /**
+     * 作用:对账单下载<br>
+     * 场景:刷卡支付、公共号支付、扫码支付、APP支付<br>
+     * 其他:无论是否成功都返回Map。若成功,返回的Map中含有return_code、return_msg、data,
+     *      其中return_code为`SUCCESS`,data为对账单数据。
+     * @param reqData 向wxpay post的请求数据
+     * @param connectTimeoutMs 连接超时时间,单位是毫秒
+     * @param readTimeoutMs 读超时时间,单位是毫秒
+     * @return 经过封装的API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> downloadBill(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String url;
+        if (this.useSandbox) {
+            url = WXPayConstants.SANDBOX_DOWNLOADBILL_URL;
+        }
+        else {
+            url = WXPayConstants.DOWNLOADBILL_URL;
+        }
+        String respStr = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs).trim();
+        Map<String, String> ret;
+        // 出现错误,返回XML数据
+        if (respStr.indexOf("<") == 0) {
+            ret = WXPayUtil.xmlToMap(respStr);
+        }
+        else {
+            // 正常返回csv数据
+            ret = new HashMap<String, String>();
+            ret.put("return_code", WXPayConstants.SUCCESS);
+            ret.put("return_msg", "sdk");
+            ret.put("data", respStr);
+        }
+        return ret;
+    }
+
+
+    /**
+     * 作用:交易保障<br>
+     * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+     * @param reqData 向wxpay post的请求数据
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> report(Map<String, String> reqData) throws Exception {
+        return this.report(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+    }
+
+
+    /**
+     * 作用:交易保障<br>
+     * 场景:刷卡支付、公共号支付、扫码支付、APP支付
+     * @param reqData 向wxpay post的请求数据
+     * @param connectTimeoutMs 连接超时时间,单位是毫秒
+     * @param readTimeoutMs 读超时时间,单位是毫秒
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> report(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String url;
+        if (this.useSandbox) {
+            url = WXPayConstants.SANDBOX_REPORT_URL;
+        }
+        else {
+            url = WXPayConstants.REPORT_URL;
+        }
+        String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+        return WXPayUtil.xmlToMap(respXml);
+    }
+
+
+    /**
+     * 作用:转换短链接<br>
+     * 场景:刷卡支付、扫码支付
+     * @param reqData 向wxpay post的请求数据
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> shortUrl(Map<String, String> reqData) throws Exception {
+        return this.shortUrl(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+    }
+
+
+    /**
+     * 作用:转换短链接<br>
+     * 场景:刷卡支付、扫码支付
+     * @param reqData 向wxpay post的请求数据
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> shortUrl(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String url;
+        if (this.useSandbox) {
+            url = WXPayConstants.SANDBOX_SHORTURL_URL;
+        }
+        else {
+            url = WXPayConstants.SHORTURL_URL;
+        }
+        String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+        return this.processResponseXml(respXml);
+    }
+
+
+    /**
+     * 作用:授权码查询OPENID接口<br>
+     * 场景:刷卡支付
+     * @param reqData 向wxpay post的请求数据
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> authCodeToOpenid(Map<String, String> reqData) throws Exception {
+        return this.authCodeToOpenid(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
+    }
+
+
+    /**
+     * 作用:授权码查询OPENID接口<br>
+     * 场景:刷卡支付
+     * @param reqData 向wxpay post的请求数据
+     * @param connectTimeoutMs 连接超时时间,单位是毫秒
+     * @param readTimeoutMs 读超时时间,单位是毫秒
+     * @return API返回数据
+     * @throws Exception
+     */
+    public Map<String, String> authCodeToOpenid(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
+        String url;
+        if (this.useSandbox) {
+            url = WXPayConstants.SANDBOX_AUTHCODETOOPENID_URL;
+        }
+        else {
+            url = WXPayConstants.AUTHCODETOOPENID_URL;
+        }
+        String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
+        return this.processResponseXml(respXml);
+    }
+
+
+} // end class

+ 53 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/wx/sdk/WXPayConfig.java

@@ -0,0 +1,53 @@
+package com.fdkankan.pay.wx.sdk;
+
+import java.io.InputStream;
+
+public interface WXPayConfig {
+
+
+    /**
+     * 获取 App ID
+     *
+     * @return App ID
+     */
+    public String getAppID();
+
+
+    /**
+     * 获取 Mch ID
+     *
+     * @return Mch ID
+     */
+    public String getMchID();
+
+
+    /**
+     * 获取 API 密钥
+     *
+     * @return API密钥
+     */
+    public String getKey();
+
+
+    /**
+     * 获取商户证书内容
+     *
+     * @return 商户证书内容
+     */
+    public InputStream getCertStream();
+
+    /**
+     * HTTP(S) 连接超时时间,单位毫秒
+     *
+     * @return
+     */
+    public int getHttpConnectTimeoutMs();
+
+    /**
+     * HTTP(S) 读数据超时时间,单位毫秒
+     *
+     * @return
+     */
+    public int getHttpReadTimeoutMs();
+
+}

+ 45 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/wx/sdk/WXPayConstants.java

@@ -0,0 +1,45 @@
+package com.fdkankan.pay.wx.sdk;
+
+/**
+ * 常量
+ */
+public class WXPayConstants {
+
+    public enum SignType {
+        MD5, HMACSHA256
+    }
+
+    public static final String FAIL     = "FAIL";
+    public static final String SUCCESS  = "SUCCESS";
+    public static final String HMACSHA256 = "HMAC-SHA256";
+    public static final String MD5 = "MD5";
+
+    public static final String FIELD_SIGN = "sign";
+    public static final String FIELD_SIGN_TYPE = "sign_type";
+
+    public static final String MICROPAY_URL     = "https://api.mch.weixin.qq.com/pay/micropay";
+    public static final String UNIFIEDORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+    public static final String ORDERQUERY_URL   = "https://api.mch.weixin.qq.com/pay/orderquery";
+    public static final String REVERSE_URL      = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
+    public static final String CLOSEORDER_URL   = "https://api.mch.weixin.qq.com/pay/closeorder";
+    public static final String REFUND_URL       = "https://api.mch.weixin.qq.com/secapi/pay/refund";
+    public static final String REFUNDQUERY_URL  = "https://api.mch.weixin.qq.com/pay/refundquery";
+    public static final String DOWNLOADBILL_URL = "https://api.mch.weixin.qq.com/pay/downloadbill";
+    public static final String REPORT_URL       = "https://api.mch.weixin.qq.com/payitil/report";
+    public static final String SHORTURL_URL     = "https://api.mch.weixin.qq.com/tools/shorturl";
+    public static final String AUTHCODETOOPENID_URL = "https://api.mch.weixin.qq.com/tools/authcodetoopenid";
+
+    // sandbox
+    public static final String SANDBOX_MICROPAY_URL     = "https://api.mch.weixin.qq.com/sandboxnew/pay/micropay";
+    public static final String SANDBOX_UNIFIEDORDER_URL = "https://api.mch.weixin.qq.com/sandboxnew/pay/unifiedorder";
+    public static final String SANDBOX_ORDERQUERY_URL   = "https://api.mch.weixin.qq.com/sandboxnew/pay/orderquery";
+    public static final String SANDBOX_REVERSE_URL      = "https://api.mch.weixin.qq.com/sandboxnew/secapi/pay/reverse";
+    public static final String SANDBOX_CLOSEORDER_URL   = "https://api.mch.weixin.qq.com/sandboxnew/pay/closeorder";
+    public static final String SANDBOX_REFUND_URL       = "https://api.mch.weixin.qq.com/sandboxnew/secapi/pay/refund";
+    public static final String SANDBOX_REFUNDQUERY_URL  = "https://api.mch.weixin.qq.com/sandboxnew/pay/refundquery";
+    public static final String SANDBOX_DOWNLOADBILL_URL = "https://api.mch.weixin.qq.com/sandboxnew/pay/downloadbill";
+    public static final String SANDBOX_REPORT_URL       = "https://api.mch.weixin.qq.com/sandboxnew/payitil/report";
+    public static final String SANDBOX_SHORTURL_URL     = "https://api.mch.weixin.qq.com/sandboxnew/tools/shorturl";
+    public static final String SANDBOX_AUTHCODETOOPENID_URL = "https://api.mch.weixin.qq.com/sandboxnew/tools/authcodetoopenid";
+
+}

+ 307 - 0
4dkankan-pay/src/main/java/com/fdkankan/pay/wx/sdk/WXPayUtil.java

@@ -0,0 +1,307 @@
+package com.fdkankan.pay.wx.sdk;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.WriterException;
+import com.google.zxing.common.BitMatrix;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.security.MessageDigest;
+import java.util.*;
+
+
+public class WXPayUtil {
+
+    /**
+     * XML格式字符串转换为Map
+     *
+     * @param strXML XML字符串
+     * @return XML数据转换后的Map
+     * @throws Exception
+     */
+    public static Map<String, String> xmlToMap(String strXML) throws Exception {
+        Map<String, String> data = new HashMap<String, String>();
+        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+
+        // 禁用XML外部实体注入
+        /**
+         * XXE
+         * XML 外部实体注入漏洞(XML External Entity Injection,简称 XXE),
+         * 是一种容易被忽视,但危害巨大的漏洞。它可以利用 XML 外部实体加载注入,
+         * 执行不可预控的代码,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。
+         */
+
+        /**
+         * 原理:
+         * 通常,我们在使用微信支付时,商家会有一个通知的 URL 来接收异步支付结果。
+         * 然而,微信在 JAVA 版本的 SDK 存在一个 XXE 漏洞来处理这个结果。
+         * 由此攻击者可以向通知的 URL 中构建恶意的回调数据,以便根据需要窃取商家服务器上的任意信息。
+         * 一旦攻击者获得商家的关键安全密钥(md5-key 和merchant-Id),
+         * 那么他们可以通过发送伪造的信息来欺骗商家而无需付费购买任意商品。
+         */
+        documentBuilderFactory.setExpandEntityReferences(false);
+        documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
+        InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
+        org.w3c.dom.Document doc = documentBuilder.parse(stream);
+        doc.getDocumentElement().normalize();
+        NodeList nodeList = doc.getDocumentElement().getChildNodes();
+        for (int idx=0; idx<nodeList.getLength(); ++idx) {
+            Node node = nodeList.item(idx);
+            if (node.getNodeType() == Node.ELEMENT_NODE) {
+                org.w3c.dom.Element element = (org.w3c.dom.Element) node;
+                data.put(element.getNodeName(), element.getTextContent());
+            }
+        }
+        try {
+            stream.close();
+        }
+        catch (Exception ex) {
+
+        }
+        return data;
+    }
+
+    /**
+     * 将Map转换为XML格式的字符串
+     *
+     * @param data Map类型数据
+     * @return XML格式的字符串
+     * @throws Exception
+     */
+    public static String mapToXml(Map<String, String> data) throws Exception {
+        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
+        org.w3c.dom.Document document = documentBuilder.newDocument();
+        org.w3c.dom.Element root = document.createElement("xml");
+        document.appendChild(root);
+        for (String key: data.keySet()) {
+            String value = data.get(key);
+            if (value == null) {
+                value = "";
+            }
+            value = value.trim();
+            org.w3c.dom.Element filed = document.createElement(key);
+            filed.appendChild(document.createTextNode(value));
+            root.appendChild(filed);
+        }
+        TransformerFactory tf = TransformerFactory.newInstance();
+        Transformer transformer = tf.newTransformer();
+        DOMSource source = new DOMSource(document);
+        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+        StringWriter writer = new StringWriter();
+        StreamResult result = new StreamResult(writer);
+        transformer.transform(source, result);
+        String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
+        try {
+            writer.close();
+        }
+        catch (Exception ex) {
+        }
+        return output;
+    }
+
+
+    /**
+     * 生成带有 sign 的 XML 格式字符串
+     *
+     * @param data Map类型数据
+     * @param key API密钥
+     * @return 含有sign字段的XML
+     */
+    public static String generateSignedXml(final Map<String, String> data, String key) throws Exception {
+        return generateSignedXml(data, key, WXPayConstants.SignType.MD5);
+    }
+
+    /**
+     * 生成带有 sign 的 XML 格式字符串
+     *
+     * @param data Map类型数据
+     * @param key API密钥
+     * @param signType 签名类型
+     * @return 含有sign字段的XML
+     */
+    public static String generateSignedXml(final Map<String, String> data, String key, WXPayConstants.SignType signType) throws Exception {
+        String sign = generateSignature(data, key, signType);
+        data.put(WXPayConstants.FIELD_SIGN, sign);
+        return mapToXml(data);
+    }
+
+
+    /**
+     * 判断签名是否正确
+     *
+     * @param xmlStr XML格式数据
+     * @param key API密钥
+     * @return 签名是否正确
+     * @throws Exception
+     */
+    public static boolean isSignatureValid(String xmlStr, String key) throws Exception {
+        Map<String, String> data = xmlToMap(xmlStr);
+        if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
+            return false;
+        }
+        String sign = data.get(WXPayConstants.FIELD_SIGN);
+        return generateSignature(data, key).equals(sign);
+    }
+
+    /**
+     * 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。
+     *
+     * @param data Map类型数据
+     * @param key API密钥
+     * @return 签名是否正确
+     * @throws Exception
+     */
+    public static boolean isSignatureValid(Map<String, String> data, String key) throws Exception {
+        return isSignatureValid(data, key, WXPayConstants.SignType.MD5);
+    }
+
+    /**
+     * 判断签名是否正确,必须包含sign字段,否则返回false。
+     *
+     * @param data Map类型数据
+     * @param key API密钥
+     * @param signType 签名方式
+     * @return 签名是否正确
+     * @throws Exception
+     */
+    public static boolean isSignatureValid(Map<String, String> data, String key, WXPayConstants.SignType signType) throws Exception {
+        if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
+            return false;
+        }
+        String sign = data.get(WXPayConstants.FIELD_SIGN);
+        return generateSignature(data, key, signType).equals(sign);
+    }
+
+    /**
+     * 生成签名
+     *
+     * @param data 待签名数据
+     * @param key API密钥
+     * @return 签名
+     */
+    public static String generateSignature(final Map<String, String> data, String key) throws Exception {
+        return generateSignature(data, key, WXPayConstants.SignType.MD5);
+    }
+
+    /**
+     * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
+     *
+     * @param data 待签名数据
+     * @param key API密钥
+     * @param signType 签名方式
+     * @return 签名
+     */
+    public static String generateSignature(final Map<String, String> data, String key, WXPayConstants.SignType signType) throws Exception {
+        Set<String> keySet = data.keySet();
+        String[] keyArray = keySet.toArray(new String[keySet.size()]);
+        Arrays.sort(keyArray);
+        StringBuilder sb = new StringBuilder();
+        for (String k : keyArray) {
+            if (k.equals(WXPayConstants.FIELD_SIGN)) {
+                continue;
+            }
+            if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
+                sb.append(k).append("=").append(data.get(k).trim()).append("&");
+        }
+        sb.append("key=").append(key);
+        if (WXPayConstants.SignType.MD5.equals(signType)) {
+            return MD5(sb.toString()).toUpperCase();
+        }
+        else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {
+            return HMACSHA256(sb.toString(), key);
+        }
+        else {
+            throw new Exception(String.format("Invalid sign_type: %s", signType));
+        }
+    }
+
+
+    /**
+     * 获取随机字符串 Nonce Str
+     *
+     * @return String 随机字符串
+     */
+    public static String generateNonceStr() {
+        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
+    }
+
+
+    /**
+     * 生成 MD5
+     *
+     * @param data 待处理数据
+     * @return MD5结果
+     */
+    public static String MD5(String data) throws Exception {
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        byte[] array = md.digest(data.getBytes("UTF-8"));
+        StringBuilder sb = new StringBuilder();
+        for (byte item : array) {
+            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
+        }
+        return sb.toString().toUpperCase();
+    }
+
+    /**
+     * 生成 HMACSHA256
+     * @param data 待处理数据
+     * @param key 密钥
+     * @return 加密结果
+     * @throws Exception
+     */
+    public static String HMACSHA256(String data, String key) throws Exception {
+        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
+        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
+        sha256_HMAC.init(secret_key);
+        byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
+        StringBuilder sb = new StringBuilder();
+        for (byte item : array) {
+            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
+        }
+        return sb.toString().toUpperCase();
+    }
+
+    /**
+     * 根据url生成二位图片对象
+     *
+     * @param codeUrl
+     * @return
+     * @throws WriterException
+     */
+    public static BufferedImage getQRCodeImge(String codeUrl) throws WriterException {
+        int width = 300;
+        //根据url生成二维码
+        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
+        // 设置二维码参数
+        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
+        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
+        BitMatrix bitMatrix = multiFormatWriter.encode(codeUrl, BarcodeFormat.QR_CODE, width, width, hints);
+        BufferedImage image = new BufferedImage(width, width, 1);
+        for(int x = 0; x < width; ++x) {
+            for(int y = 0; y < width; ++y) {
+                image.setRGB(x, y, bitMatrix.get(x, y) ? -16777216 : -1);
+            }
+        }
+        return image;
+
+    }
+}

+ 2 - 1
pom.xml

@@ -7,13 +7,14 @@
         <module>4dkankan-common</module>
         <module>4dkankan-gateway</module>
         <module>4dkankan-center-scene</module>
-<!--        <module>4dkankan-center-platform</module>-->
+        <module>4dkankan-center-platform</module>
         <module>4dkankan-pom</module>
         <module>4dkankan-center-api</module>
         <module>4dkankan-center-auth</module>
         <module>4dkankan-center-log</module>
         <module>4dkankan-center-modeling</module>
         <module>4dkankan-center-statistics</module>
+        <module>4dkankan-pay</module>
     </modules>
 
     <parent>