Selaa lähdekoodia

API对接接口

Aslee 3 vuotta sitten
vanhempi
commit
ffb060a9b5
77 muutettua tiedostoa jossa 8616 lisäystä ja 80 poistoa
  1. 1 12
      pom.xml
  2. 0 26
      src/main/java/caimei/controller/OrderApi.java
  3. 0 18
      src/main/java/caimei/controller/ProductApi.java
  4. 1 1
      src/main/java/com/caimei/PurchaseApplication.java
  5. 1 1
      src/main/java/com/caimei/components/RedisService.java
  6. 1 1
      src/main/java/com/caimei/config/ApiConfig.java
  7. 1 1
      src/main/java/com/caimei/config/ApiInterceptor.java
  8. 1 1
      src/main/java/com/caimei/config/FastDfsClient.java
  9. 1 1
      src/main/java/com/caimei/config/GlobalCorsConfig.java
  10. 1 1
      src/main/java/com/caimei/config/GlobalTokenAspect.java
  11. 1 1
      src/main/java/com/caimei/config/SwaggerConfig.java
  12. 132 0
      src/main/java/com/caimei/controller/OrderApi.java
  13. 83 0
      src/main/java/com/caimei/controller/ProductApi.java
  14. 16 0
      src/main/java/com/caimei/mapper/OrganizeMapper.java
  15. 41 0
      src/main/java/com/caimei/mapper/ProductMapper.java
  16. 1 1
      src/main/java/com/caimei/model/ResponseJson.java
  17. 10 0
      src/main/java/com/caimei/model/enumerate/KeyFormat.java
  18. 75 0
      src/main/java/com/caimei/model/enumerate/ReceivablesType.java
  19. 61 0
      src/main/java/com/caimei/model/po/BpOrderInvoicePo.java
  20. 76 0
      src/main/java/com/caimei/model/po/BpOrderUserInfoPo.java
  21. 37 0
      src/main/java/com/caimei/model/po/CmApiOrganizePo.java
  22. 129 0
      src/main/java/com/caimei/model/po/CmApiOrganizeProductPo.java
  23. 172 0
      src/main/java/com/caimei/model/po/CmDiscernReceiptPo.java
  24. 312 0
      src/main/java/com/caimei/model/po/CmOrderPo.java
  25. 336 0
      src/main/java/com/caimei/model/po/CmOrderProductPo.java
  26. 187 0
      src/main/java/com/caimei/model/po/CmReturnedPurchasePo.java
  27. 359 0
      src/main/java/com/caimei/model/po/CmShopOrderPo.java
  28. 48 0
      src/main/java/com/caimei/model/po/OrderProductLadderPricePo.java
  29. 48 0
      src/main/java/com/caimei/model/po/ProductDetailInfoPo.java
  30. 46 0
      src/main/java/com/caimei/model/po/ProductImagePo.java
  31. 633 0
      src/main/java/com/caimei/model/po/ProductPo.java
  32. 390 0
      src/main/java/com/caimei/model/po/UserPo.java
  33. 51 0
      src/main/java/com/caimei/model/vo/AddressInfoVo.java
  34. 93 0
      src/main/java/com/caimei/model/vo/AddressVo.java
  35. 55 0
      src/main/java/com/caimei/model/vo/CmOrderVo.java
  36. 22 0
      src/main/java/com/caimei/model/vo/DiscernReceiptVo.java
  37. 73 0
      src/main/java/com/caimei/model/vo/DisplayOrderProductVo.java
  38. 38 0
      src/main/java/com/caimei/model/vo/LadderPriceVo.java
  39. 54 0
      src/main/java/com/caimei/model/vo/OrderProductVo.java
  40. 69 0
      src/main/java/com/caimei/model/vo/OrderVo.java
  41. 78 0
      src/main/java/com/caimei/model/vo/ProductDetailVo.java
  42. 66 0
      src/main/java/com/caimei/model/vo/ProductListVo.java
  43. 168 0
      src/main/java/com/caimei/model/vo/ProductVo.java
  44. 45 0
      src/main/java/com/caimei/service/OrderService.java
  45. 29 0
      src/main/java/com/caimei/service/ProductService.java
  46. 1145 0
      src/main/java/com/caimei/service/impl/OrderServiceImpl.java
  47. 197 0
      src/main/java/com/caimei/service/impl/ProductServiceImpl.java
  48. 128 0
      src/main/java/com/caimei/utils/AES.java
  49. 1 1
      src/main/java/com/caimei/utils/AliyunSmsUtil.java
  50. 601 0
      src/main/java/com/caimei/utils/Base64.java
  51. 1 1
      src/main/java/com/caimei/utils/Base64Util.java
  52. 36 0
      src/main/java/com/caimei/utils/CheckUtils.java
  53. 1 1
      src/main/java/com/caimei/utils/CodeUtil.java
  54. 7 0
      src/main/java/com/caimei/utils/ConfigureEncryptAndDecrypt.java
  55. 373 0
      src/main/java/com/caimei/utils/ConvertUtils.java
  56. 165 0
      src/main/java/com/caimei/utils/Digest.java
  57. 85 0
      src/main/java/com/caimei/utils/HashUtil.java
  58. 167 0
      src/main/java/com/caimei/utils/HttpClient4Utils.java
  59. 1 1
      src/main/java/com/caimei/utils/ImageUtils.java
  60. 1 1
      src/main/java/com/caimei/utils/JwtUtil.java
  61. 23 0
      src/main/java/com/caimei/utils/KeyGenerator.java
  62. 133 0
      src/main/java/com/caimei/utils/KeyPair.java
  63. 141 0
      src/main/java/com/caimei/utils/KeyUtils.java
  64. 206 0
      src/main/java/com/caimei/utils/KeyWorker.java
  65. 366 0
      src/main/java/com/caimei/utils/MathUtil.java
  66. 1 1
      src/main/java/com/caimei/utils/Md5Util.java
  67. 1 1
      src/main/java/com/caimei/utils/OSSUtils.java
  68. 83 0
      src/main/java/com/caimei/utils/OrderNoUtils.java
  69. 128 0
      src/main/java/com/caimei/utils/ProductUtils.java
  70. 107 0
      src/main/java/com/caimei/utils/RSAUtil.java
  71. 174 0
      src/main/java/com/caimei/utils/XmlKeyBuilder.java
  72. 2 2
      src/main/resources/application.yml
  73. 3 0
      src/main/resources/backup.sql
  74. 3 3
      src/main/resources/config/dev/application-dev.yml
  75. 10 0
      src/main/resources/mapper/OrganizeMapper.xml
  76. 154 0
      src/main/resources/mapper/ProductMapper.xml
  77. 130 3
      src/test/java/caimei/PurchaseApplicationTests.java

+ 1 - 12
pom.xml

@@ -140,22 +140,11 @@
             <artifactId>fastdfs-client</artifactId>
             <version>1.26.1-RELEASE</version>
         </dependency>
-        <!--引入商品模块-->
-        <dependency>
-            <groupId>com.caimei.module</groupId>
-            <artifactId>product</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
-        </dependency>
         <dependency>
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcprov-jdk16</artifactId>
             <version>1.46</version>
         </dependency>
-        <dependency>
-            <groupId>com.caimei.module</groupId>
-            <artifactId>pay</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
-        </dependency>
         <!-- 对 HTML 富文本文档进行解析和操作 -->
         <dependency>
             <groupId>org.jsoup</groupId>
@@ -301,7 +290,7 @@
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <configuration>
                     <!-- springboot启动类目录 -->
-                    <mainClass>com.caimei.PurchaseApplication</mainClass>
+                    <mainClass>com.com.caimei.PurchaseApplication</mainClass>
                 </configuration>
                 <executions>
                     <execution>

+ 0 - 26
src/main/java/caimei/controller/OrderApi.java

@@ -1,26 +0,0 @@
-package caimei.controller;
-
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * @author Aslee
- */
-@Slf4j
-@RestController
-@RequestMapping("/order")
-public class OrderApi {
-
-    /**
-     * 下单
-     */
-
-
-    /**
-     * 订单查询
-     */
-
-
-}

+ 0 - 18
src/main/java/caimei/controller/ProductApi.java

@@ -1,18 +0,0 @@
-package caimei.controller;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * @author Aslee
- */
-@Slf4j
-@RestController
-@RequestMapping("/product")
-public class ProductApi {
-
-    /**
-     * 商品列表
-     */
-}

+ 1 - 1
src/main/java/caimei/PurchaseApplication.java → src/main/java/com/caimei/PurchaseApplication.java

@@ -1,4 +1,4 @@
-package caimei;
+package com.caimei;
 
 import com.github.tobato.fastdfs.FdfsClientConfig;
 import org.springframework.boot.SpringApplication;

+ 1 - 1
src/main/java/caimei/components/RedisService.java → src/main/java/com/caimei/components/RedisService.java

@@ -1,4 +1,4 @@
-package caimei.components;
+package com.caimei.components;
 
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;

+ 1 - 1
src/main/java/caimei/config/ApiConfig.java → src/main/java/com/caimei/config/ApiConfig.java

@@ -1,4 +1,4 @@
-package caimei.config;
+package com.caimei.config;
 
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

+ 1 - 1
src/main/java/caimei/config/ApiInterceptor.java → src/main/java/com/caimei/config/ApiInterceptor.java

@@ -1,4 +1,4 @@
-package caimei.config;
+package com.caimei.config;
 
 import com.caimei.components.RedisService;
 import com.caimei.utils.JwtUtil;

+ 1 - 1
src/main/java/caimei/config/FastDfsClient.java → src/main/java/com/caimei/config/FastDfsClient.java

@@ -1,4 +1,4 @@
-package caimei.config;
+package com.caimei.config;
 
 import com.github.tobato.fastdfs.domain.StorePath;
 import com.github.tobato.fastdfs.proto.storage.DownloadByteArray;

+ 1 - 1
src/main/java/caimei/config/GlobalCorsConfig.java → src/main/java/com/caimei/config/GlobalCorsConfig.java

@@ -1,4 +1,4 @@
-package caimei.config;
+package com.caimei.config;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;

+ 1 - 1
src/main/java/caimei/config/GlobalTokenAspect.java → src/main/java/com/caimei/config/GlobalTokenAspect.java

@@ -1,4 +1,4 @@
-package caimei.config;
+package com.caimei.config;
 
 import com.caimei.components.RedisService;
 import com.caimei.utils.JwtUtil;

+ 1 - 1
src/main/java/caimei/config/SwaggerConfig.java → src/main/java/com/caimei/config/SwaggerConfig.java

@@ -1,4 +1,4 @@
-package caimei.config;
+package com.caimei.config;
 
 import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
 import org.springframework.beans.factory.annotation.Value;

+ 132 - 0
src/main/java/com/caimei/controller/OrderApi.java

@@ -0,0 +1,132 @@
+package com.caimei.controller;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.caimei.model.ResponseJson;
+import com.caimei.service.OrderService;
+import com.caimei.utils.KeyUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Aslee
+ */
+@Slf4j
+@RestController
+@RequestMapping("/order")
+public class OrderApi {
+    private OrderService orderService;
+
+    @Autowired
+    public void setOrderService(OrderService orderService) {
+        this.orderService = orderService;
+    }
+
+
+    /**
+     * 下单
+     * data 参数格式:{
+     *                     "sign": ****,        //签名
+     *                     "notifyUrl": ****,       //订单支付完成通知回调地址
+     *                     "addressInfo": {         //收货地址信息
+     *                          "receiveMan":"收货人",     //收货人
+     *                          "mobile":"15816666666",    //手机号
+     *                          "provinceName":"广东省",   //省
+     *                          "cityName":"深圳市",       //市/县
+     *                          "townName":"福田区",       //区
+     *                          "addressDetail":"*****"   //详细地址
+     *                     },          //
+     *                     "orderId": cm6858,          //对接组织的订单Id,由组织自行生成
+     *                     "productInfo": { "0001":2,    // 商品Id:购买数量
+     *                                       "0002":3
+     *                                   }
+     *                     "payInfo": {               // 订单信息
+     *                         "orderShouldPayFee": 609.11,       //订单总金额
+     *                         "freight": "15",                   //运费金额,到付:0,深圳市内10,省内15
+     *                         "freePostFlag": 1                  //-1:到付,1:有运费
+     *                     },
+     *                     "invoiceInfo": {}// 发票信息: {"type": 0},// 不开发票
+     *                                     {
+     *                                         "type": 2,             // 要发票
+     *                                         "invoiceTitle": "单位名称",
+     *                                         "corporationTaxNum": "NSRSBM97897",
+     *                                         "registeredAddress": "注册地址",
+     *                                         "registeredPhone": "15814011616",
+     *                                         "openBank": "开户银行",
+     *                                         "bankAccountNo": "987987465465464"
+     *                                     }
+     *                 }
+     */
+    @PostMapping("/submit")
+    public ResponseJson orderSubmit(HttpServletRequest request) {
+        log.info("API对接组织下单");
+        String cmAccount = request.getParameter("cmAccount");
+        String data = request.getParameter("data");
+        if (StringUtils.isEmpty(cmAccount)) {
+            return ResponseJson.error("采美账户不能为空");
+        }
+        if (StringUtils.isEmpty(data)) {
+            return ResponseJson.error("订单数据不能为空");
+        }
+        return orderService.orderSubmit(cmAccount, data);
+    }
+
+    /**
+     * 订单详情
+     */
+    @PostMapping("/detail")
+    public ResponseJson<Map<String, Object>> orderDetail(HttpServletRequest request) {
+        String cmAccount = request.getParameter("cmAccount");
+        String data = request.getParameter("data");
+        if (StringUtils.isEmpty(cmAccount)) {
+            return ResponseJson.error("采美账户不能为空", null);
+        }
+        if (StringUtils.isEmpty(data)) {
+            return ResponseJson.error("订单数据不能为空", null);
+        }
+        return orderService.orderDetail(cmAccount, data);
+    }
+
+    /**
+     * 取消订单
+     */
+    @PostMapping("/cancel")
+    public ResponseJson orderCancel(HttpServletRequest request) {
+        String cmAccount = request.getParameter("cmAccount");
+        String data = request.getParameter("data");
+        if (StringUtils.isEmpty(cmAccount)) {
+            return ResponseJson.error("采美账户不能为空", null);
+        }
+        if (StringUtils.isEmpty(data)) {
+            return ResponseJson.error("订单数据不能为空", null);
+        }
+        return orderService.orderCancel(cmAccount, data);
+    }
+
+    /**
+     * 测试通知回调
+     */
+    @PostMapping("/pay/callBack")
+    public ResponseJson callBack(HttpServletRequest request) {
+        String cmAccount = request.getParameter("cmAccount");
+        String data = request.getParameter("data");
+        if (StringUtils.isEmpty(cmAccount)) {
+            return ResponseJson.error("采美账户不能为空", null);
+        }
+        if (StringUtils.isEmpty(data)) {
+            return ResponseJson.error("订单数据不能为空", null);
+        }
+        return orderService.payCallBack(cmAccount, data);
+    }
+}

+ 83 - 0
src/main/java/com/caimei/controller/ProductApi.java

@@ -0,0 +1,83 @@
+package com.caimei.controller;
+
+import com.caimei.model.ResponseJson;
+import com.caimei.model.vo.ProductDetailVo;
+import com.caimei.model.vo.ProductListVo;
+import com.caimei.service.ProductService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+/**
+ * @author Aslee
+ */
+@Slf4j
+@RestController
+@RequestMapping("/product")
+public class ProductApi {
+
+    private ProductService productService;
+
+    @Autowired
+    public void setOrderService(ProductService productService) {
+        this.productService = productService;
+    }
+
+    /**
+     * 商品列表
+     * data 参数格式:{
+     *     "sign":****,             //签名
+     *     "pageNum":1,             //页码
+     *     "pageSize":10,           //每页大小
+     *     "productName":精华油     //模糊查询的商品名称
+     * }
+     * return [
+     *          {
+     *              "productId": "0003",                            //商品Id
+     *             "productName": "卡琪紫红色精华油",                //商品名称
+     *             "image": "****TH2AZX5L6R20140415014819.png",     //图片路径
+     *             "price": 379.75,                                 //价格
+     *             "unit": "瓶",                                     //规格
+     *             "minBuyNumber": 1,                               //最少购买数量
+     *             "ladderPriceFlag": 0,                            //阶梯价格标识:0关闭,1开启
+     *             "ladderPriceList": null,                         //阶梯价格列表
+     *             "brandName": null                                //品牌名称
+     *          }...
+     *      ]
+     */
+    @PostMapping("/list")
+    public ResponseJson<List<ProductListVo>> productList(HttpServletRequest request){
+        String cmAccount = request.getParameter("cmAccount");
+        String data = request.getParameter("data");
+        if (StringUtils.isEmpty(cmAccount)) {
+            return ResponseJson.error("采美账户不能为空",null);
+        }
+        if (StringUtils.isEmpty(data)) {
+            return ResponseJson.error("商品数据不能为空",null);
+        }
+        return productService.productList(cmAccount, data);
+    }
+
+    /**
+     * 商品详情
+     */
+    @PostMapping("/detail")
+    public ResponseJson<ProductDetailVo> productDetail(HttpServletRequest request) {
+        String cmAccount = request.getParameter("cmAccount");
+        String data = request.getParameter("data");
+        if (StringUtils.isEmpty(cmAccount)) {
+            return ResponseJson.error("采美账户不能为空",null);
+        }
+        if (StringUtils.isEmpty(data)) {
+            return ResponseJson.error("商品数据不能为空",null);
+        }
+        return productService.productDetail(cmAccount, data);
+    }
+}

+ 16 - 0
src/main/java/com/caimei/mapper/OrganizeMapper.java

@@ -0,0 +1,16 @@
+package com.caimei.mapper;
+
+import com.caimei.model.po.CmApiOrganizePo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/6/8
+ */
+@Mapper
+public interface OrganizeMapper {
+
+    CmApiOrganizePo getOrganizeByCmAccount(String cmAccount);
+}

+ 41 - 0
src/main/java/com/caimei/mapper/ProductMapper.java

@@ -0,0 +1,41 @@
+package com.caimei.mapper;
+
+import com.caimei.model.po.CmApiOrganizeProductPo;
+import com.caimei.model.po.ProductDetailInfoPo;
+import com.caimei.model.po.ProductImagePo;
+import com.caimei.model.po.ProductPo;
+import com.caimei.model.vo.LadderPriceVo;
+import com.caimei.model.vo.OrderProductVo;
+import com.caimei.model.vo.ProductVo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/6/9
+ */
+@Mapper
+public interface ProductMapper {
+
+    CmApiOrganizeProductPo getProductByProductId(String productId);
+
+    List<LadderPriceVo> getLadderPriceByProductId(Integer id);
+
+    List<LadderPriceVo> findLadderPriceByProductId(Integer productID);
+
+    ProductPo findPostFeeProduct();
+
+    List<ProductVo> getProductList(@Param("organizeId") Integer organizeId,@Param("productName") String productName);
+
+    ProductVo findProductByProductId(@Param("organizeId") Integer organizeId, @Param("productId") String productId);
+
+    List<ProductImagePo> findProductImagesByOriginalId(Integer originalProductId);
+
+    ProductDetailInfoPo findProductDetailByOriginalId(Integer originalProductId);
+
+    List<OrderProductVo> getOrderProduct(Long orderID);
+}

+ 1 - 1
src/main/java/caimei/model/ResponseJson.java → src/main/java/com/caimei/model/ResponseJson.java

@@ -1,4 +1,4 @@
-package caimei.model;
+package com.caimei.model;
 
 import lombok.Data;
 

+ 10 - 0
src/main/java/com/caimei/model/enumerate/KeyFormat.java

@@ -0,0 +1,10 @@
+package com.caimei.model.enumerate;
+
+/*
+2015-01-23
+*/
+public enum KeyFormat {
+    ASN,
+    XML,
+    PEM
+}

+ 75 - 0
src/main/java/com/caimei/model/enumerate/ReceivablesType.java

@@ -0,0 +1,75 @@
+package com.caimei.model.enumerate;
+/**
+ *支付类型枚举类
+ *
+ * @author Aslee
+ */
+public enum ReceivablesType {
+    JIANSHE(1, "建设银行-7297"),
+    GUANGFA(2, "广发银行-0115"),
+    ZHONGXING_1(3, "中信银行-7172"),
+    ZHONGXING_2(4, "中信银行-0897"),
+    ZHONGXING_2_1(5, "中信银行-0897-财付通"),
+    ZHONGXING_2_2(6, "中信银行-0897-支付宝"),
+    XIANSHANG_ZFB(7, "线上-支付宝"),
+    XIANSHANG_WX(8, "线上-微信支付"),
+    XIANSHANG_KUAIQIAN(9, "线上-快钱支付"),
+    KOUTOUFANYONG(10, "口头返佣"),
+    GUANGFA_1(11, "广发银行-5461"),
+    WANGYIN(12, "企业网银"),
+    PCWX(13, "微信支付"),
+    ZHIFUBAO(14, "支付宝"),
+    MINIWX(15, "微信支付"),
+    YUEDIKO(16, "余额抵扣");
+
+
+    private int code;
+    private String desc;
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public void setDesc(String desc) {
+        this.desc = desc;
+    }
+
+    ReceivablesType(int code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public static String getReceivablesType(int code) {
+        for (ReceivablesType type : ReceivablesType.values()) {
+            if (type.getCode() == code) {
+                return type.desc;
+            }
+        }
+        return "";
+    }
+
+    public static ReceivablesType getReceivablesType(String desc) {
+        for (ReceivablesType type : ReceivablesType.values()) {
+            if (type.getDesc().contains(desc)) {
+                return type;
+            }
+        }
+        return null;
+    }
+
+    public static Boolean havaHandlingFee(int code) {
+        boolean res = false;
+        if (ReceivablesType.ZHONGXING_2_1.getCode() == code || ReceivablesType.ZHONGXING_2_2.getCode() == code || ReceivablesType.ZHONGXING_2.getCode() == code || ReceivablesType.GUANGFA_1.getCode() == code) {
+            res = true;
+        }
+        return res;
+    }
+}

+ 61 - 0
src/main/java/com/caimei/model/po/BpOrderInvoicePo.java

@@ -0,0 +1,61 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * bp_order_invoice
+ * @author 
+ */
+@Data
+public class BpOrderInvoicePo implements Serializable {
+    private Long id;
+
+    /**
+     * 订单ID
+     */
+    private Long orderId;
+
+    /**
+     * 发票抬头
+     */
+    private String invoiceTitle;
+
+    /**
+     * 发票类型0不开发票 1普通发票 2增值税发票
+     */
+    private Long type;
+
+    /**
+     * 发票内容
+     */
+    private String invoiceContent;
+
+    /**
+     * 企业税号
+     */
+    private String corporationTaxNum;
+
+    /**
+     * 注册地址
+     */
+    private String registeredAddress;
+
+    /**
+     * 注册电话
+     */
+    private String registeredPhone;
+
+    /**
+     * 开户银行账户
+     */
+    private String bankAccountNo;
+
+    /**
+     * 开户银行
+     */
+    private String openBank;
+
+    private static final long serialVersionUID = 1L;
+}

+ 76 - 0
src/main/java/com/caimei/model/po/BpOrderUserInfoPo.java

@@ -0,0 +1,76 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * bp_order_userinfo
+ *
+ * @author
+ */
+@Data
+public class BpOrderUserInfoPo implements Serializable {
+    private Long id;
+
+    /**
+     * 订单ID
+     */
+    private Long orderId;
+
+    private Long clubId;
+
+    private Long userId;
+
+    /**
+     * 买家
+     */
+    private String name;
+
+    /**
+     * 收货人
+     */
+    private String shouHuoRen;
+
+    /**
+     * 手机
+     */
+    private String mobile;
+
+    /**
+     * 电话
+     */
+    private String phone;
+
+    /**
+     * 邮编
+     */
+    private String postalCode;
+
+    /**
+     * 县区ID
+     */
+    private Integer townId;
+
+    /**
+     * 省、直辖市
+     */
+    private String province;
+
+    /**
+     * 市
+     */
+    private String city;
+
+    /**
+     * 县、区
+     */
+    private String town;
+
+    /**
+     * 收货地址
+     */
+    private String address;
+
+    private static final long serialVersionUID = 1L;
+}

+ 37 - 0
src/main/java/com/caimei/model/po/CmApiOrganizePo.java

@@ -0,0 +1,37 @@
+package com.caimei.model.po;
+
+
+import lombok.Data;
+
+/**
+ * 采美接口对接组织管理
+ * @author Aslee
+ * @date  2021-06-08
+ */
+@Data
+public class CmApiOrganizePo {
+	/**
+	 * 组织id
+	 */
+	private Integer organizeId;
+	/**
+	 * 用户id
+	 */
+	private Integer userId;
+	/**
+	 * 采美账户
+	 */
+	private String cmAccount;
+	/**
+	 * 公钥
+	 */
+	private String publicKey;
+	/**
+	 * 组织私钥
+	 */
+	private String privateKey;
+	/**
+	 * 支付完成回调接口
+	 */
+	private String notifyUrl;
+}

+ 129 - 0
src/main/java/com/caimei/model/po/CmApiOrganizeProductPo.java

@@ -0,0 +1,129 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * cm_api_organize_product
+ *
+ * @author
+ */
+@Data
+public class CmApiOrganizeProductPo implements Serializable {
+    private Integer id;
+
+    /**
+     * 组织Id
+     */
+    private Integer organizeId;
+
+    /**
+     * 商品Id
+     */
+    private Integer productId;
+
+    /**
+     * 启用阶梯价格标识 0否 1是
+     */
+    private Integer ladderPriceFlag;
+
+    /**
+     * 机构价
+     */
+    private BigDecimal price;
+
+    /**
+     * 是否含税   0不含税,1含税,2未知
+     */
+    private Integer includedTax;
+
+    /**
+     * 发票类型(基于是否含税基础)   1增值税专用发票,2增值税普通发票, 3不能开票
+     */
+    private Integer invoiceType;
+
+    /**
+     * 最小起订量
+     */
+    private Integer minBuyNumber;
+
+    /**
+     * 成本价类型:1固定成本 2比例成本
+     */
+    private Integer costType;
+
+    /**
+     * 机构税率 :增值税默认13%,普通票6%取值范围[0-100]
+     */
+    private BigDecimal clubTaxPoint;
+
+    /**
+     * 供应商税率:增值专用发票默认13%,增值税普通发票6%取值范围[0-100]
+     */
+    private BigDecimal shopTaxPoint;
+
+    /**
+     * 成本价
+     */
+    private BigDecimal costPrice;
+
+    /**
+     * 比例成本百分比
+     */
+    private BigDecimal costProportional;
+
+    /**
+     * 商品状态:0已下架,1已上架
+     */
+    private Integer status;
+
+    /**
+     * 添加时间
+     */
+    private Date addTime;
+
+    /**
+     * 删除标识:0未删除,1已删除
+     */
+    private Integer delFlag;
+
+    /**
+     * 是否开启促销活动,1开启,0不开启
+     */
+    private Integer actStatus;
+
+    /**
+     * 供应商id
+     */
+    private Integer shopId;
+
+    /**
+     * 规格
+     */
+    private String unit;
+
+    /**
+     * 市场价
+     */
+    private BigDecimal normalPrice;
+
+    /**
+     * 商品名称
+     */
+    private String name;
+
+    /**
+     * 商品主图
+     */
+    private String mainImage;
+
+    /**
+     * 供应商名称
+     */
+    private String shopName;
+
+    private static final long serialVersionUID = 1L;
+}

+ 172 - 0
src/main/java/com/caimei/model/po/CmDiscernReceiptPo.java

@@ -0,0 +1,172 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * cm_discern_receipt
+ * @author
+ */
+@Data
+public class CmDiscernReceiptPo implements Serializable {
+    private Long id;
+
+    /**
+     * 用户付款方式:1线上,2线下,3余额抵扣
+     */
+    private String payWay;
+
+    /**
+     * 付款类型:1建设银行7297、2广发银行0115、3中信银行7172、4中信银行0897、5中信银行0897-财付通、6中信银行0897-支付宝、7线上-支付宝、8线上-微信支付、9线上-快钱支付、10口头返佣、11广发银行5461
+     */
+    private String payType;
+
+    /**
+     * 收款款项类型:1订单款,2非订单款,3返佣款
+     */
+    private String receiptType;
+
+    /**
+     * 收款状态:1待确认、2已确认(待审核)、3审核通过、4审核未通过、5收款撤销【订单款项状态:12345】【非订单款项状态:125】【返佣款状态:125】【线上支付成功为审核通过】
+     */
+    private String receiptStatus;
+
+    /**
+     * 短信内容
+     */
+    private String smsContent;
+
+    /**
+     * 短信内容Md5加密串(适用于二次短信匹配查询)
+     */
+    private String smsMd5Code;
+
+    /**
+     * 短信订单标识内容
+     */
+    private String orderFlag;
+
+    /**
+     * 收款金额(线上一次性付款和支付金额一致)
+     */
+    private BigDecimal receiptAmount;
+
+    /**
+     * 手续费(个别银行存在手续费)
+     */
+    private BigDecimal handlingFee;
+
+    /**
+     * 确认订单类型:1小额抹平确认,2大额抹平确认,3大额退款余额,4确认关联
+     */
+    private String confirmType;
+
+    /**
+     * 确认人权限ID(对应receipt_user_permission表)
+     */
+    private Long confirmUserPermissionID;
+
+    /**
+     * 审核人权限ID(对应receipt_user_permission表)
+     */
+    private Long reviewUserPermissionID;
+
+    /**
+     * 撤销人ID(对应sys_user表)
+     */
+    private Long cancelUserPermissionID;
+
+    /**
+     * 交易号--[线上字段]
+     */
+    private String transactionNum;
+
+    /**
+     * 银行Id--[线上字段]
+     */
+    private Integer bankID;
+
+    /**
+     * 银行卡号--[线上字段]
+     */
+    private String bankCode;
+
+    /**
+     * 快钱支付类型ID--[线上字段]
+     */
+    private Integer kuaiQianPayTypeID;
+
+    /**
+     * 块钱支付ID--[线上字段]
+     */
+    private Integer kuaiQianPayerID;
+
+    /**
+     * 支付状态 1支付成功--[线上字段]
+     */
+    private String rePayFlag;
+
+    /**
+     * 支付金额(可能废弃如果只需要一个支付就使用receiptAmount)--[线上字段]
+     */
+    private Double actualAmount;
+
+    /**
+     * 支付回调返回数据--[线上字段]
+     */
+    private String formData;
+
+    /**
+     * 支付问题--[线上字段]
+     */
+    private String problem;
+
+    /**
+     * 非订单款说明(适用协销确认的时候区分订单和非订单款)
+     */
+    private String noOrderReason;
+
+    /**
+     * 审核不通过原因
+     */
+    private String reviewReason;
+
+    /**
+     * 撤销原因
+     */
+    private String cancelReason;
+
+    /**
+     * 收款时间
+     */
+    private String receiptDate;
+
+    /**
+     * 确认时间
+     */
+    private String confirmDate;
+
+    /**
+     * 审核时间
+     */
+    private String reviewDate;
+
+    /**
+     * 撤销时间
+     */
+    private String cancelDate;
+
+    /**
+     * 更新操作时间
+     */
+    private String updateDate;
+
+    /**
+     * 作废标记 0 否,其余是
+     */
+    private String delFlag;
+
+    private static final long serialVersionUID = 1L;
+}

+ 312 - 0
src/main/java/com/caimei/model/po/CmOrderPo.java

@@ -0,0 +1,312 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * cm_order
+ *
+ * @author
+ */
+@Data
+public class CmOrderPo implements Serializable {
+  private Long orderID;
+
+  /**
+   * 订单编号
+   */
+  private String orderNo;
+
+  /**
+   * 对接组织的订单Id,由组织自行生成
+   */
+  private String apiOrganizeOrderId;
+
+  /**
+   * 采美组织默认为null,具体对应cm_mall_organize表ID
+   */
+  private Integer organizeID;
+
+  private Long userID;
+
+  /**
+   * 下单人
+   */
+  private Integer buyUserID;
+
+  /**
+   * 子订单ID
+   */
+  private String shopOrderIDs;
+
+  /**
+   * 0:个人自己下单 1:企业自己下单 2:员工帮会所下单 3:协销帮会所下单  4:后台下单 5:采美豆订单
+   */
+  private Integer orderSubmitType;
+
+  /**
+   * 订单类型 协销订单 0 普通订单 1
+   */
+  private Integer orderType;
+
+  /**
+   * 是否包含活动商品(受订单未支付自动关闭时间影响)  0 否 1 是
+   */
+  private String hasActProduct;
+
+  /**
+   * 订单自动关闭时间点单位毫秒(v5.0版本已废弃)
+   */
+  private BigDecimal autoCloseTimeMills;
+
+  /**
+   * 0待确认,11待收待发,12待收部发,13待收全发,21部收待发,22部收部发,23部收全发,31已收待发,32已收部发,33已收全发,4交易完成,5订单完成,6已关闭,7交易全退
+   */
+  private String status;
+
+  /**
+   * (收款买家)收款状态:1待收款、2部分收款、3已收款
+   */
+  private String receiptStatus;
+
+  /**
+   * (付款供应商)付款状态:1待付款、2部分付款、3已付款
+   */
+  private String payStatus;
+
+  /**
+   * 发货状态:1待发货、2部分发货、3已发货
+   */
+  private String sendOutStatus;
+
+  /**
+   * 退货退款类型:1部分退、2全部退
+   */
+  private String refundType;
+
+  /**
+   * 已支付成功次数统计(适用线上多笔付款用来确认当前是哪一笔)
+   */
+  private Integer paySuccessCounter;
+
+  /**
+   * 是否已支付 未支付0 已支付1
+   */
+  private String payFlag;
+
+  /**
+   * 是否能走线上支付 0可以 1不可以 只能线下
+   */
+  private String onlinePayFlag;
+
+  /**
+   * 商品总金额 (商品单价乘以数量,再加上税费)
+   */
+  private BigDecimal productTotalFee;
+
+  /**
+   * 小计金额 (商品折后单价乘以数量,再加上税费)
+   */
+  private BigDecimal orderTotalFee;
+
+  /**
+   * 订单总额(小计金额减去经理折扣后,再加上运费)
+   */
+  private BigDecimal payTotalFee;
+
+  /**
+   * 真实支付金额(订单总额减去抵扣的账户余额)
+   */
+  private BigDecimal payableAmount;
+
+  /**
+   * 余额支付金额
+   */
+  private BigDecimal balancePayFee;
+
+  /**
+   * 总优惠 自助下单活动优惠 协销下单price-折后单价
+   */
+  private BigDecimal preferential;
+
+  /**
+   * 经理折扣
+   */
+  private BigDecimal discountFee;
+
+  /**
+   * 促销满减优惠
+   */
+  private BigDecimal promotionFullReduction;
+
+  private Long spID;
+
+  private Long mainSpID;
+
+  /**
+   * 订单备注
+   */
+  private String note;
+
+  /**
+   * 会所ID
+   */
+  private Long clubID;
+
+  /**
+   * 会所扫描确认时间
+   */
+  private String clubScanTime;
+
+  /**
+   * 支付方式,(协销订单可能会存在多种进账方式用,隔开)(v5.0版本已废弃)
+   */
+  private String payWay;
+
+  /**
+   * 订单来源  1WWW 2 CRM 3APP[历史数据] 4客服 5外单 6星范等小程序
+   */
+  private String orderSource;
+
+  /**
+   * 订单取消时间
+   */
+  private String closeTime;
+
+  /**
+   * 订单确认时间
+   */
+  private String confirmTime;
+
+  /**
+   * 订单支付时间
+   */
+  private String payTime;
+
+  /**
+   * 订单提交时间
+   */
+  private String orderTime;
+
+  /**
+   * 购买总数
+   */
+  private Integer productCount;
+
+  /**
+   * 赠送总数  不计算价格
+   */
+  private Integer presentCount;
+
+  /**
+   * 促销赠品总数
+   */
+  private Integer promotionalGiftsCount;
+
+  /**
+   * 库分期免息状态 0、免息 1、不免息[V5.0.0版本已废弃]
+   */
+  private String cooFreeFlag;
+
+  /**
+   * 库分期分期费率[V5.0.0版本已废弃]
+   */
+  private Integer cooFreeRate;
+
+  /**
+   * 库分期免息金额[V5.0.0版本已废弃]
+   */
+  private BigDecimal cooFreeAmount;
+
+  /**
+   * 是否开发票 没开发票 0 开个人发票 1 开企业发票2
+   */
+  private String invoiceFlag;
+
+  /**
+   * 订单确认标志,0否,1后台确认,2买家确认(适用协销订单并且1或2都算已确认订单,主动订单默认1为确认)
+   */
+  private String confirmFlag;
+
+  /**
+   * 条款ID
+   */
+  private Long clauseID;
+
+  /**
+   * 条款内容
+   */
+  private String clauseContent;
+
+  /**
+   * 条款名称
+   */
+  private String clauseName;
+
+  /**
+   * 更新时间
+   */
+  private String updateDate;
+
+  /**
+   * 免邮标志  运费:-1到付,0包邮,1需要运费,-2仪器到付其它包邮
+   */
+  private String freePostFlag;
+
+  /**
+   * -1到付,0包邮,大于0具体金额,-2仪器到付其它包邮(且运费已使用商品形式存储)
+   */
+  private BigDecimal freight;
+
+  /**
+   * 订单状态 0 有效  其它无效
+   */
+  private String delFlag;
+
+  /**
+   * 包邮券ID  保留字段
+   */
+  private Integer freePostageTicketID;
+
+  /**
+   * 订单是否可拆分   1可拆分 0不可拆分
+   */
+  private String splitFlag;
+
+  /**
+   * 订单取消原因
+   */
+  private String closeReason;
+
+  /**
+   * 邮费订单标识 1是邮费订单  0不是邮费订单
+   */
+  private String postageOrderFlag;
+
+  /**
+   * 第三方订单编号(绑定第三方订单关系),适用第三方发起订单
+   */
+  private String thirdPartyOrderNo;
+
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * 二手商品订单标识  0非二手商品订单、 1二手商品订单
+   */
+  private String secondHandOrderFlag;
+
+  /**
+   * 确认付款供应商标识 0未确认,1已确认
+   */
+  private String affirmPaymentFlag;
+
+  /**
+   * 返佣订单标识 0非返佣订单,1返佣订单
+   */
+  private String rebateFlag;
+
+  /** 订单0成本标识*/
+  private Integer zeroCostFlag;
+}

+ 336 - 0
src/main/java/com/caimei/model/po/CmOrderProductPo.java

@@ -0,0 +1,336 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * cm_order_product
+ * @author 
+ */
+@Data
+public class CmOrderProductPo implements Serializable {
+    private Integer orderProductID;
+
+    /**
+     * 主订单编号
+     */
+    private String orderNo;
+
+    /**
+     * 主订单ID
+     */
+    private Long orderID;
+
+    /**
+     * 订单Id
+     */
+    private Integer shopOrderID;
+
+    /**
+     * 子订单编号
+     */
+    private String shopOrderNo;
+
+    /**
+     * 供应商ID
+     */
+    private Long shopID;
+
+    /**
+     * 商品Id(采美商城和组织小程序都保存product表ID)
+     */
+    private Integer productID;
+
+    /**
+     * api组织的商品Id,关联cm_mall_organize_products表ID[适用于组织订单]
+     */
+    private Integer organizeProductID;
+
+    /**
+     * 采美组织默认为null,具体对应cm_mall_organize表ID[适用于组织订单]
+     */
+    private Integer organizeID;
+
+    /**
+     * 购买数量
+     */
+    private Integer num;
+
+    /**
+     * 赠送数量
+     */
+    private Integer presentNum;
+
+    /**
+     * 出库类型 0 采美出库  1 供应商出库
+     */
+    private String outStoreType;
+
+    /**
+     * skuId
+     */
+    private Integer skuID;
+
+    /**
+     * sku属性
+     */
+    private String props;
+
+    /**
+     * 属性名
+     */
+    private String propName;
+
+    /**
+     * 商品编号
+     */
+    private String productNo;
+
+    /**
+     * 商品价格(协销 市场价 普通 购买价)
+     */
+    private BigDecimal price;
+
+    /**
+     * 市场价 = 商品表市场价
+     */
+    private BigDecimal normalPrice;
+
+    /**
+     * 购买时商品成本价
+     */
+    private BigDecimal costPrice;
+
+    /**
+     * 记录普通用户购买时价格  活动价优先
+     */
+    private BigDecimal price0;
+
+    /**
+     * 记录会员用户购买时价格  活动价优先
+     */
+    private BigDecimal price1;
+
+    /**
+     * 总价  = price X num
+     */
+    private BigDecimal totalAmount;
+
+    /**
+     * 总价  = discountPrice X num + totalAddedValueTax
+     */
+    private BigDecimal totalFee;
+
+    /**
+     * 应付金额 = totalFee - discountFee
+     */
+    private BigDecimal shouldPayFee;
+
+    /**
+     * 折扣比例
+     */
+    private BigDecimal discount;
+
+    /**
+     * 折后单价
+     */
+    private BigDecimal discountPrice;
+
+    /**
+     * 是否含税 0不含税 1含税 2未知
+     */
+    private String includedTax;
+
+    /**
+     * 发票类型 1增值税专用发票 2增值税普通发票 3不开发票
+     */
+    private String invoiceType;
+
+    /**
+     * 启用阶梯价格标识 0否 1是
+     */
+    private String ladderPriceFlag;
+
+    /**
+     * 后台设置该商品税率
+     */
+    private BigDecimal taxRate;
+
+    /**
+     * 供应商税率:增值专用发票默认13%,增值税普通发票6%取值范围[0-100]
+     */
+    private BigDecimal supplierTaxRate;
+
+    /**
+     * 单个税费=税率X折后单价 
+     */
+    private BigDecimal addedValueTax;
+
+    /**
+     * 总税费=单个税费X购买数量
+     */
+    private BigDecimal totalAddedValueTax;
+
+    /**
+     * 总税费(应付税费)默认值和应收税费一样
+     */
+    private BigDecimal shouldPayTotalTax;
+
+    /**
+     * 单个付供应商税费
+     */
+    private BigDecimal singleShouldPayTotalTax;
+
+    /**
+     * 商品费
+     */
+    private BigDecimal shopProductAmount;
+
+    /**
+     * 该商品总的应付供应商金额
+     */
+    private BigDecimal shopFee;
+
+    /**
+     * 该商品总的应付第三方金额
+     */
+    private BigDecimal otherFee;
+
+    /**
+     * 该商品总的应付采美金额 (受赠品影响)
+     */
+    private BigDecimal cmFee;
+
+    /**
+     * 后台设置的单个应付供应商金额
+     */
+    private BigDecimal singleShopFee;
+
+    /**
+     * 后台设置单个应付第三方金额
+     */
+    private BigDecimal singleOtherFee;
+
+    /**
+     * 后台计算的单个应付采美金额
+     */
+    private BigDecimal singleCmFee;
+
+    /**
+     * 订单商品状态
+     */
+    private String status;
+
+    /**
+     * 是否已评论:1是,空或0未评论(V5.0.0版本后已废弃--)
+     */
+    private String commentFlag;
+
+    /**
+     * 获取到的总采美豆值
+     */
+    private BigDecimal totalBeans;
+
+    /**
+     * 使用余额金额
+     */
+    private Double useBalanceAmount;
+
+    /**
+     * 使用采美豆数量
+     */
+    private Integer useBeanAmount;
+
+    /**
+     * 未出库数量
+     */
+    private Integer notOutStore;
+
+    /**
+     * 当前采美豆专区价格(采美豆)
+     */
+    private Integer cmbeanPrice;
+
+    /**
+     * 下单时商品购买价格类型快照 0 机构价,1活动价 ,2阶梯价
+     */
+    private String isActProduct;
+
+    /**
+     * 是否是赠品 0 不是 1 是
+     */
+    private String isGiftProduct;
+
+    /**
+     * 活动信息 已享受满XX减XX 之类
+     */
+    private String productActInfo;
+
+    /**
+     * 订单商品再次购买标识 0否 1是
+     */
+    private String buyAgainFlag;
+
+    /**
+     * 订单商品供应商确认标志 0否 1是
+     */
+    private String confirmProductFlag;
+
+    /**
+     * 支付状态 0 未进账 1 待财务审核 2 已进账(适用协销的单笔线下进账和自助订单线下或异常进账)
+     */
+    private String payStatus;
+
+    /**
+     * 供应商名称
+     */
+    private String shopName;
+
+    /**
+     * 商品名称
+     */
+    private String name;
+
+    /**
+     * 商品单位
+     */
+    private String productUnit;
+
+    private String productImage;
+
+    /**
+     * 活动类型 1000 热卖 1001 团购 1003 满减 1004满赠 1005 买赠
+     */
+    private String actType;
+
+    /**
+     * 活动优惠  类似满减优惠金额
+     */
+    private BigDecimal actPreferential;
+
+    /**
+     * 商品类型(0正常商品,1协商赠品,2促销赠品)
+     */
+    private String productType;
+
+    /**
+     * 订单促销id
+     */
+    private Integer orderPromotionsId;
+
+    /**
+     * 优惠 (price - discountPrice) * num 
+     */
+    private BigDecimal preferential;
+
+    /**
+     * 协销订单:经理折扣(平摊到每个商品上,  按照每种商品的总价占订单总价的比例来均分);普通订单 无
+     */
+    private BigDecimal discountFee;
+
+    private Integer cancelNum;
+
+    private static final long serialVersionUID = 1L;
+}

+ 187 - 0
src/main/java/com/caimei/model/po/CmReturnedPurchasePo.java

@@ -0,0 +1,187 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * cm_returned_purchase
+ * @author
+ */
+@Data
+public class CmReturnedPurchasePo implements Serializable {
+    private Long id;
+
+    /**
+     * 退款退货编号
+     */
+    private String returnedNo;
+
+    /**
+     * 主订单ID
+     */
+    private Long orderID;
+
+    /**
+     * 用户ID(买家)
+     */
+    private Long userID;
+
+    /**
+     * 状态:1待审核、2审核通过、3审核不通过
+     */
+    private String status;
+
+    /**
+     * 退款方式 1有支付有退款(退款方式可多选具体参考以上金额)、4未支付无退款(未支付发起退款)
+     */
+    private Integer returnedWay;
+
+    /**
+     * 付款方式 付款方式 1建设银行7297, 2中信银行0897, 3中信银行7172, 4广发银行0115, 5广发银行5461
+     */
+    private String payType;
+
+    /**
+     * 发起该操作时订单状态快照:0待确认,11待收待发,12待收部发,13待收全发,21部收待发,22部收部发,23部收全发,31已收待发,32已收部发,33已收全发,4交易完成,5订单完成,6已关闭,7交易全退
+     */
+    private String operatingOrderStatus;
+
+    /**
+     * 退款银行信息(银行名称、户名、开户行、银行账号)【V6.1.1版本已废弃拆分显示】
+     */
+    private String returnedBankInfo;
+
+    /**
+     * 银行账户名
+     */
+    private String bankAccountName;
+
+    /**
+     * 开户银行账户
+     */
+    private String bankAccountNo;
+
+    /**
+     * 开户银行
+     */
+    private String openBank;
+
+    /**
+     * 账户类型:1公账,2私账
+     */
+    private String bankAccountType;
+
+    /**
+     * 退款(退货)总金额【此金额为不包含经理折扣和余额抵扣的商品退款金额记录不作实际退款用,适用二次退款抵扣经理计算】
+     */
+    private BigDecimal returnedPurchaseFee;
+
+    /**
+     * 退款总额(给买家)
+     */
+    private BigDecimal refundFee;
+
+    /**
+     * 退账户余额
+     */
+    private BigDecimal refundBalanceFee;
+
+    /**
+     * 退线上退回
+     */
+    private BigDecimal refundOnlineFee;
+
+    /**
+     * 退线下转账
+     */
+    private BigDecimal refundOfflineFee;
+
+    /**
+     * 凭证图片1
+     */
+    private String image1;
+
+    /**
+     * 凭证图片2
+     */
+    private String image2;
+
+    /**
+     * 凭证图片3
+     */
+    private String image3;
+
+    /**
+     * 凭证图片4
+     */
+    private String image4;
+
+    /**
+     * 凭证图片5
+     */
+    private String image5;
+
+    /**
+     * 审核凭证图片1
+     */
+    private String reviewImage1;
+
+    /**
+     * 审核凭证图片2
+     */
+    private String reviewImage2;
+
+    /**
+     * 审核凭证图片3
+     */
+    private String reviewImage3;
+
+    /**
+     * 审核凭证图片4
+     */
+    private String reviewImage4;
+
+    /**
+     * 审核凭证图片5
+     */
+    private String reviewImage5;
+
+    /**
+     * 备注信息
+     */
+    private String remarks;
+
+    /**
+     * 审核备注信息
+     */
+    private String reviewRemarks;
+
+    /**
+     * 申请人ID
+     */
+    private Long applicationUserID;
+
+    /**
+     * 申请退款时间
+     */
+    private String returnTime;
+
+    /**
+     * 审核人ID
+     */
+    private Long reviewUserID;
+
+    /**
+     * 确认退款时间(审核退款时间)
+     */
+    private String confirmReturnTime;
+
+    /**
+     * 是否有效状态 0 有效  其它无效(适用取消退款等)
+     */
+    private String delFlag;
+
+    private static final long serialVersionUID = 1L;
+}

+ 359 - 0
src/main/java/com/caimei/model/po/CmShopOrderPo.java

@@ -0,0 +1,359 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * cm_shop_order
+ * @author 
+ */
+@Data
+public class CmShopOrderPo implements Serializable {
+    /**
+     * 子订单ID
+     */
+    private Integer shopOrderID;
+
+    /**
+     * 子订单编号
+     */
+    private String shopOrderNo;
+
+    /**
+     * 订单编号
+     */
+    private String orderNo;
+
+    /**
+     * 主订单ID
+     */
+    private Long orderID;
+
+    /**
+     * 采美组织默认为null,具体对应cm_mall_organize表ID
+     */
+    private Integer organizeID;
+
+    /**
+     * 用户Id
+     */
+    private Integer userID;
+
+    /**
+     * 供应商Id
+     */
+    private Integer shopID;
+
+    /**
+     * 订单促销id(主要针对店铺促销)
+     */
+    private Integer orderPromotionsId;
+
+    /**
+     * 普通订单 1 协销订单0 与cm_order一样
+     */
+    private Integer orderType;
+
+    /**
+     * 0:个人自己下单 1:企业自己下单 2:员工帮会所下单 3:协销帮会所下单  4:后台下单 5:采美豆订单
+     */
+    private Integer orderSubmitType;
+
+    /**
+     * 赠品数
+     */
+    private Integer presentNum;
+
+    /**
+     *   购买数量
+     */
+    private Integer itemCount;
+
+    /**
+     * 已经发货的商品数量
+     */
+    private Integer outStoreNum;
+
+    /**
+     * 子订单发货批次 默认值 = 0 即没过发货
+     */
+    private Integer outStoreTimes;
+
+    /**
+     * 收货地址县区Id
+     */
+    private Integer townID;
+
+    /**
+     * 子订单备注信息
+     */
+    private String note;
+
+    /**
+     * 运费:-1到付,0包邮,其他为具体运费(v5.0版本已废弃,运费已使用商品形式存储)
+     */
+    private Double fee;
+
+    /**
+     * 余额支付时使用的金额
+     */
+    private BigDecimal accountAmount;
+
+    /**
+     * 总金额 = 订单商品totalAmount
+     */
+    private BigDecimal productAmount;
+
+    /**
+     * 总价 = totalFee
+     */
+    private BigDecimal totalAmount;
+
+    /**
+     * 需要支付金额 shouldPayFee +运费
+     */
+    private BigDecimal needPayAmount;
+
+    private BigDecimal discountAmount;
+
+    /**
+     * 经理折扣(v5.0版本已废弃,经理折扣只和主订单有关)
+     */
+    private BigDecimal discountFee;
+
+    /**
+     * 订单总优惠
+     */
+    private BigDecimal preferential;
+
+    /**
+     * 促销满减优惠(不考虑凑单促销)
+     */
+    private BigDecimal promotionFullReduction;
+
+    /**
+     * 是否已支付:1是,0否
+     */
+    private String payFlag;
+
+    /**
+     * 订单提交时间
+     */
+    private String orderTime;
+
+    /**
+     * 支付时间
+     */
+    private String payTime;
+
+    /**
+     * 订单完成时间
+     */
+    private String finishTime;
+
+    /**
+     * 订单彻底完成时间 不能售后 毫秒
+     */
+    private Long autoOverTimeMills;
+
+    /**
+     * 订单状态:见表c_orderstatus或枚举OrderStatus(v5.0版本已废弃只有主订单状态)
+     */
+    private Integer status;
+
+    /**
+     * (付款供应商)付款状态:1待付款、2部分付款、3已付款
+     */
+    private String payStatus;
+
+    /**
+     * 发货状态:1待发货、2部分发货、3已发货
+     */
+    private String sendOutStatus;
+
+    private Integer refundStatus;
+
+    private Integer returnGoodsStatus;
+
+    /**
+     * 收货时间
+     */
+    private String receiveGoodsTime;
+
+    /**
+     * 自动收货时间点 毫秒计算 
+     */
+    private Long autoReceiveTimeMills;
+
+    /**
+     * 总税费
+     */
+    private BigDecimal totalAddedValueTax;
+
+    /**
+     * 可退款金额 = 余额抵扣金额
+     */
+    private Double canRefundAmount;
+
+    /**
+     * 退款金额
+     */
+    private Double refundAmount;
+
+    private Integer clubID;
+
+    private Integer spID;
+
+    private Integer mainSpID;
+
+    /**
+     * 订单采美豆个数
+     */
+    private Integer orderBeanAmount;
+
+    /**
+     * 使用采美豆数量
+     */
+    private Integer useBeanAmount;
+
+    /**
+     * 是否使用采美豆
+     */
+    private Integer useBeanFlag;
+
+    /**
+     * 是否可以退货 1可以退款/退货 0不可退款/退货
+     */
+    private Integer canRefundFlag;
+
+    /**
+     * 是否使用余额
+     */
+    private Integer useBalanceFlag;
+
+    /**
+     * 可以退还的采美豆个数
+     */
+    private Integer canRefundBeans;
+
+    /**
+     * 订单包邮时本该支付的运费
+     */
+    private BigDecimal freePostageFee;
+
+    /**
+     * 使用的包邮券Id,为空表示未使用包邮券  保留
+     */
+    private Integer freePostageTicketID;
+
+    /**
+     * 佣金 =  应付采美
+     */
+    private BigDecimal brokerage;
+
+    /**
+     * 后台删除状态 0正常,其他删除
+     */
+    private String delFlag;
+
+    /**
+     * 订单退款金额
+     */
+    private BigDecimal refundsAmount;
+
+    /**
+     * 订单状态标识,1:非退货退款订单、2:退货退款中、3退货退款完成
+     */
+    private String orderStatusFlag;
+
+    /**
+     * 购买状态
+     */
+    private String buyStatus;
+
+    /**
+     * 全部发货时间
+     */
+    private String deliveryTimeMills;
+
+    private Integer orderDeliveryID;
+
+    /**
+     * 订单能否拆分 1 为可拆分, 0为不可拆分
+     */
+    private String splitFlag;
+
+    /**
+     * 是否处于给供应商状态中   0不是的,  1是的
+     */
+    private String paying;
+
+    /**
+     * 商品费
+     */
+    private BigDecimal shopProductAmount;
+
+    /**
+     * 运费
+     */
+    private BigDecimal shopPostFee;
+
+    /**
+     * 税费
+     */
+    private BigDecimal shopTaxFee;
+
+    /**
+     * 付供应商 = 商品费 + 运费 + 税费
+     */
+    private BigDecimal shouldPayShopAmount;
+
+    /**
+     * 已付款金额
+     */
+    private BigDecimal payedShopAmount;
+
+    /**
+     * 付第三方
+     */
+    private BigDecimal shopOtherFee;
+
+    private String receiptedFlag;
+
+    private String receiptedType;
+
+    /**
+     * 固定成本1,  比例成本2  为空就是还没有设置过
+     */
+    private String costType;
+
+    /**
+     * 比例成本的比例值
+     */
+    private BigDecimal proportional;
+
+    /**
+     * 修改应付必填备注信息
+     */
+    private String modifyShouldPayNote;
+
+    /**
+     * 修改应付金额的用户ID
+     */
+    private Long modifyShouldPayUserID;
+
+    /**
+     * 修改应付金额的时间
+     */
+    private Date modifyShouldPayDate;
+
+    /**
+     * 子订单0成本标识:0子订单不是0成本,1子订单0成本(子订单中所有商品成本为0)
+     */
+    private Integer zeroCostFlag;
+
+    private static final long serialVersionUID = 1L;
+}

+ 48 - 0
src/main/java/com/caimei/model/po/OrderProductLadderPricePo.java

@@ -0,0 +1,48 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * order_product_ladder_price
+ * @author 
+ */
+@Data
+public class OrderProductLadderPricePo implements Serializable {
+    private Integer id;
+
+    /**
+     * 订单商品Id
+     */
+    private Integer orderProductId;
+
+    /**
+     * 第几阶梯
+     */
+    private Integer ladderNum;
+
+    /**
+     * 购买数量
+     */
+    private Integer buyNum;
+
+    /**
+     * 购买价格
+     */
+    private BigDecimal buyPrice;
+
+    /**
+     * 创建时间
+     */
+    private Date createDate;
+
+    /**
+     * 更新时间
+     */
+    private Date updateDate;
+
+    private static final long serialVersionUID = 1L;
+}

+ 48 - 0
src/main/java/com/caimei/model/po/ProductDetailInfoPo.java

@@ -0,0 +1,48 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * productdetailinfo
+ * @author
+ */
+@Data
+public class ProductDetailInfoPo implements Serializable {
+    private Integer productDetailInfoId;
+
+    /**
+     * 商品Id
+     */
+    private Integer productId;
+
+    private String propValueAlias;
+
+    private String propValueImages;
+
+    /**
+     * 商品详情信息
+     */
+    private String detailInfo;
+
+    private String detailInfoTxt;
+
+    private String seoTitle;
+
+    private String seoKeyword;
+
+    private String seoDes;
+
+    /**
+     * 服务详情
+     */
+    private String serviceInfo;
+
+    /**
+     * 订购方案
+     */
+    private String orderInfo;
+
+    private static final long serialVersionUID = 1L;
+}

+ 46 - 0
src/main/java/com/caimei/model/po/ProductImagePo.java

@@ -0,0 +1,46 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * productimage
+ * @author
+ */
+@Data
+public class ProductImagePo implements Serializable {
+    private Integer productImageId;
+
+    /**
+     * 商品Id
+     */
+    private Integer productId;
+
+    /**
+     * 商品对应供应商Id
+     */
+    private Integer shopId;
+
+    /**
+     * 添加时间
+     */
+    private String addTime;
+
+    /**
+     * 图片
+     */
+    private String image;
+
+    /**
+     * 是否主图:1是,空或0不是
+     */
+    private String mainFlag;
+
+    /**
+     * 排序值
+     */
+    private Integer sortIndex;
+
+    private static final long serialVersionUID = 1L;
+}

+ 633 - 0
src/main/java/com/caimei/model/po/ProductPo.java

@@ -0,0 +1,633 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * product
+ *
+ * @author
+ */
+@Data
+public class ProductPo implements Serializable {
+    private Integer productID;
+
+    /**
+     * 品牌Id
+     */
+    private Integer brandID;
+
+    /**
+     * 一级分类ID
+     */
+    private Integer bigTypeID;
+
+    /**
+     * 二级分类ID
+     */
+    private Integer smallTypeID;
+
+    /**
+     * 三级分类Id
+     */
+    private Integer tinyTypeID;
+
+    /**
+     * 小程序商品分类Id(已废弃)
+     */
+    private Integer classifyId;
+
+    /**
+     * 商品的类别:1正常商品(默认),2二手商品
+     */
+    private String productCategory;
+
+    /**
+     * 常用商品001,精品推荐010,热门推荐100,三者同时存在111
+     */
+    private Integer preferredFlag;
+
+    private Integer selfTypeID;
+
+    /**
+     * 所属供应商Id
+     */
+    private Integer shopID;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 内部商品名称
+     */
+    private String aliasName;
+
+    /**
+     * 搜索关键词,4个用双##区分,不存在的直接逗号隔空(顺序参考:品牌,学名,市场称呼,大类别,小类别)
+     */
+    private String searchKey;
+
+    /**
+     * 商品备注
+     */
+    private String productRemarks;
+
+    /**
+     * 市场价
+     */
+    private Double normalPrice;
+
+    private Double price;
+
+    /**
+     * 最低价【V6.2.0版本已废弃】
+     */
+    private Double highestUserLevelPrice;
+
+    /**
+     * 最高价【V6.2.0版本已废弃】
+     */
+    private Double lowestUserLevelPrice;
+
+    /**
+     * 最高价会员等级【V6.2.0版本已废弃】
+     */
+    private Integer lowestUserLevelID;
+
+    /**
+     * 普通用户价格,【V6.2.0版本已废弃】
+     */
+    private Double price0;
+
+    /**
+     * 普通用户价格等级(范围1-5)【V6.2.0版本已废弃】
+     */
+    private String price0Grade;
+
+    /**
+     * 普通用户价格文字【V6.2.0版本已废弃】
+     */
+    private String price0Text;
+
+    /**
+     * 普通用户文字展示标志 0显示价格 1显示文字 2显示等级【V6.2.0版本已废弃】
+     */
+    private String price0TextFlag;
+
+    /**
+     * 机构价格(同为二手商品的交易价)
+     */
+    private Double price1;
+
+    /**
+     * 机构用户价格等级(范围1-5)【V6.2.0版本已废弃-根据价格范围显示等级】
+     */
+    private String price1Grade;
+
+    /**
+     * 机构用户价格文字【V6.2.0版本已废弃-目前都是前端直接写死】
+     */
+    private String price1Text;
+
+    /**
+     * 是否公开机构价 0公开价格 1不公开价格 2仅对会员机构公开
+     */
+    private String price1TextFlag;
+
+    /**
+     * 游客价格【V6.2.0版本已废弃】
+     */
+    private Double price8;
+
+    /**
+     * 游客用户价格等级(范围1-5)【V6.2.0版本已废弃】
+     */
+    private String price8Grade;
+
+    /**
+     * 游客价格文字【V6.2.0版本已废弃】
+     */
+    private String price8Text;
+
+    /**
+     * 游客用户文字展示标志 0显示价格 1显示文字 2显示等级【V6.2.0版本已废弃】
+     */
+    private String price8TextFlag;
+
+    /**
+     * 启用阶梯价格标识 0否 1是
+     */
+    private String ladderPriceFlag;
+
+    /**
+     * 银卡价【V6.2.0版本已废弃】
+     */
+    private Double price2;
+
+    /**
+     * 金卡价【V6.2.0版本已废弃】
+     */
+    private Double price3;
+
+    /**
+     * 铂金价【V6.2.0版本已废弃】
+     */
+    private Double price4;
+
+    /**
+     * 钻石价【V6.2.0版本已废弃】
+     */
+    private Double price5;
+
+    /**
+     * 普通服务商价【V6.2.0版本已废弃】
+     */
+    private Double price6;
+
+    /**
+     * 金牌服务商价【V6.2.0版本已废弃】
+     */
+    private Double price7;
+
+    /**
+     * 运费【V6.2.0版本已废弃】
+     */
+    private Double fee;
+
+    /**
+     * 库存(同为二手商品的数量)
+     */
+    private Integer stock;
+
+    /**
+     * 是否有sku:1有, 0没有
+     */
+    private String hasSkuFlag;
+
+    /**
+     * 主图
+     */
+    private String mainImage;
+
+    /**
+     * sku属性
+     */
+    private String propertiesInfo;
+
+    /**
+     * 添加时间
+     */
+    private String addTime;
+
+    /**
+     * 更新时间
+     */
+    private String updateTime;
+
+    /**
+     * 小程序分类添加时间(已废弃)
+     */
+    private Date classifyAddTime;
+
+    /**
+     * 销量
+     */
+    private Integer sellNumber;
+
+    private Integer weekSellNumber;
+
+    private String beforeValidFlag;
+
+    /**
+     * 商品状态,见表c_productstatus或枚举ProductStatus,0逻辑删除 1待审核 2已上架 3已下架 8审核未通过 9已隐身 10已冻结
+     */
+    private String validFlag;
+
+    /**
+     * 收藏量
+     */
+    private Integer favoriteTimes;
+
+    /**
+     * 评论分数
+     */
+    private Double commentScore;
+
+    /**
+     * 评论次数
+     */
+    private Integer commentTimes;
+
+    private String selfRecommendFlag;
+
+    private String sysRecommendFlag;
+
+    /**
+     * 排序值
+     */
+    private Integer sortIndex;
+
+    /**
+     * 供应商主推商品标志 0否 1是
+     */
+    private String featuredFlag;
+
+    /**
+     * 供应商主推商品排序
+     */
+    private Integer featuredSortIndex;
+
+    /**
+     * 商品货号
+     */
+    private String productCode;
+
+    private Double rate1;
+
+    private Double rate2;
+
+    /**
+     * 包装规格
+     */
+    private String unit;
+
+    /**
+     * 是否推送到ERP,1已推送, 空或0未推送
+     */
+    private String synToERPFlag;
+
+    /**
+     * 销售区域:1全部区域, 0指定区域
+     */
+    private String allAreaFlag;
+
+    /**
+     * 指定的销售区域
+     */
+    private String provinceIDs;
+
+    /**
+     * 服务起订量
+     */
+    private String serviceNumber;
+
+    /**
+     * 最大购买量
+     */
+    private Integer maxBuyNumber;
+
+    private String virtualFlag;
+
+    /**
+     * 最小购买量
+     */
+    private Integer minBuyNumber;
+
+    /**
+     * 最小包装数量
+     */
+    private Integer packageCount;
+
+    /**
+     * 运费:0买家承担, 1卖家承担
+     */
+    private String byFlag;
+
+    /**
+     * 普通商品标志 1是
+     */
+    private Integer normalProductFlag;
+
+    private Integer wholeSaleProductFlag;
+
+    private Integer promotionProductFlag;
+
+    private Integer groupBuyProductFlag;
+
+    /**
+     * 购买数量: 1逐步增长,2以起订量增长(起订量的倍数增长)
+     */
+    private Integer step;
+
+    private String speCommisionFlag;
+
+    private Double speCommision;
+
+    private String videourl;
+
+    private String props;
+
+    private String providers;
+
+    private Double serviceCommissionRatio;
+
+    private Double reCommissionRatio;
+
+    /**
+     * 推送到ERP的原商品名称 name字段的名称可能做修改已适应平台的搜索
+     */
+    private String pushToERPName;
+
+    private Integer prodBeans;
+
+    /**
+     * 该商品是否可以使用采美豆购买
+     */
+    private Integer useBeansFlag;
+
+    /**
+     * 0开放市场 1私有市场
+     */
+    private Integer privateFlag;
+
+    private String invisibleServiceProviderIDs;
+
+    private String displayOnCRMFlag;
+
+    private String needServiceFlag;
+
+    /**
+     * 是否使用活动角标:1是,空或0不是[与actType搭配使用,仅用于标识非真正活动]
+     */
+    private Integer actFlag;
+
+    /**
+     * 商品是否处于活动状态:1是,空或0不是[活动商品和actFlag含义不同]
+     */
+    private Integer actStatus;
+
+    /**
+     * 活动商品排序
+     */
+    private Long actSort;
+
+    /**
+     * 普通用户活动价格【V6.2.0版本已废弃】
+     */
+    private BigDecimal actPrice0;
+
+    /**
+     * 机构活动价(对应actStatus的活动下使用)
+     */
+    private BigDecimal actPrice1;
+
+    /**
+     * 银卡会员活动价【V6.2.0版本已废弃】
+     */
+    private BigDecimal actPrice2;
+
+    /**
+     * 金卡会员活动价【V6.2.0版本已废弃】
+     */
+    private BigDecimal actPrice3;
+
+    /**
+     * 铂金会员活动价【V6.2.0版本已废弃】
+     */
+    private BigDecimal actPrice4;
+
+    /**
+     * 钻石会员活动价【V6.2.0版本已废弃】
+     */
+    private BigDecimal actPrice5;
+
+    /**
+     * 普通服务商活动价【V6.2.0版本已废弃】
+     */
+    private BigDecimal actPrice6;
+
+    /**
+     * 金牌服务商活动价【V6.2.0版本已废弃】
+     */
+    private BigDecimal actPrice7;
+
+    /**
+     * 首页活动角标标识类型:1推荐热销、2推荐上新
+     */
+    private Integer actType;
+
+    /**
+     * 活动创建时间(对应actStatus的活动下使用)
+     */
+    private Date actCreateTime;
+
+    /**
+     * 满减金额(达到该金额后可享直减)
+     */
+    private BigDecimal actFullReduceAmount;
+
+    /**
+     * 购买直减金额(达到满金额后)
+     */
+    private BigDecimal actReduceAmount;
+
+    /**
+     * 商品可见度:(3:所有人可见,2:普通机构可见,1:会员机构可见)
+     */
+    private String visibility;
+
+    /**
+     * 满增金额(达到满赠金额后可享赠品) 【V6.4.2版本已废弃】
+     */
+    private BigDecimal actFullGiftAmount;
+
+    /**
+     * 买赠数量(达到该数量后可享赠品)【V6.4.2版本已废弃】
+     */
+    private Long actBuyGiftNum;
+
+    /**
+     * 活动开始时间(对应actStatus的活动下使用)
+     */
+    private Date beginTime;
+
+    /**
+     * 活动结束时间(对应actStatus的活动下使用)
+     */
+    private Date endTime;
+
+    /**
+     * 【V6.2.0版本已废弃】
+     */
+    private Integer shopIndexModuleID;
+
+    /**
+     * 上架时间
+     */
+    private Date onlineTime;
+
+    /**
+     * 下架时间
+     */
+    private Date downlineTime;
+
+    /**
+     * 是否包邮 0包邮 1到付 2默认(遵循运费规则)
+     */
+    private String freePostFlag;
+
+    /**
+     * crm一级商品分类
+     */
+    private Integer crmBigTypeId;
+
+    /**
+     * crm二级商品分类
+     */
+    private Integer crmSmallTypeId;
+
+    /**
+     * 成本价
+     */
+    private BigDecimal costPrice;
+
+    /**
+     * 比例成本百分比
+     */
+    private BigDecimal costProportional;
+
+    /**
+     * 成本价选中标志:1固定成本 2比例成
+     */
+    private String costCheckFlag;
+
+    private String precisehKey;
+
+    private Double docBoost;
+
+    /**
+     * 是否采美豆专区商品(0 否,1 是)
+     */
+    private String cmbeanFlag;
+
+    /**
+     * 采美豆专区价格(采美豆)
+     */
+    private Integer cmbeanPrice;
+
+    /**
+     * 采美豆专区排序(值越大越前)
+     */
+    private Short cmbeanSort;
+
+    /**
+     * 商品标签用英文逗号隔开,中文逗号或其它一律不作切割
+     */
+    private String tags;
+
+    private String surplusTime;
+
+    /**
+     * 商品类型:0其它类型(默认),1妆字号,2械字号
+     */
+    private String productType;
+
+    /**
+     * 械字号类型   (基于械字号基础) ,1:一类,2:二类,3:三类
+     */
+    private String machineType;
+
+    /**
+     * 械字号资质证书图 (基于械字号基础)
+     */
+    private String qualificationImg;
+
+    /**
+     * 是否含税   0不含税,1含税,2未知
+     */
+    private String includedTax;
+
+    /**
+     * 开票税点(基于不含税基础) :增值税默认13%,普通票6%取值范围[0-100]
+     */
+    private BigDecimal taxPoint;
+
+    /**
+     * 供应商税率:增值专用发票默认13%,增值税普通发票6%取值范围[0-100]
+     */
+    private BigDecimal supplierTaxPoint;
+
+    /**
+     * 发票类型(基于是否含税基础)   1增值税票,2普通票, 3不能开票
+     */
+    private String invoiceType;
+
+    /**
+     * 相关推荐类型 0自动选择; 1手动推荐
+     */
+    private String recommendType;
+
+    private Integer skuID;
+
+    /**
+     * V6.2.0版本已废弃】
+     */
+    private String priceType;
+
+    /**
+     * 商品组合Id、(cm_product_combination表Id)
+     */
+    private Integer combinationID;
+
+    /**
+     * 组合商品排序
+     */
+    private Integer combinationSort;
+
+    /**
+     * 商品属性:1产品,2仪器
+     */
+    private String commodityType;
+
+    /**
+     * 供应商名称
+     */
+    private String shopName;
+
+    private static final long serialVersionUID = 1L;
+}

+ 390 - 0
src/main/java/com/caimei/model/po/UserPo.java

@@ -0,0 +1,390 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * user
+ * @author 
+ */
+@Data
+public class UserPo implements Serializable {
+    private Integer userID;
+
+    /**
+     * 采美组织默认为0,具体对应cm_api_organize表ID
+     */
+    private Integer apiOrganizeId;
+
+    /**
+     * 企业账号名【供应商,目前只存数据不能用于登录】
+     */
+    private String account;
+
+    /**
+     * 个人手机号码(协销)
+     */
+    private String mobile;
+
+    /**
+     * 企业绑定手机号(机构,供应商)
+     */
+    private String bindMobile;
+
+    /**
+     * 用户权限 0游客 1 普通用户 2 会员机构 3 供应商 4 协销 5 普通机构【V6.2.0版本后0和1不存在】
+     */
+    private Integer userPermission;
+
+    /**
+     * 用户身份 0、个人 1、协销 2、会员机构 3、供应商 4.普通机构【V6.2.0版本后0不存在】
+     */
+    private Integer userIdentity;
+
+    /**
+     * 邮箱
+     */
+    private String email;
+
+    /**
+     * 用户名(机构联系人,供应商简称)
+     */
+    private String userName;
+
+    /**
+     * 真实姓名(供应商的联系人,机构不使用)
+     */
+    private String realName;
+
+    /**
+     * 注册来源: 0网站 1小程序
+     */
+    private String source;
+
+    /**
+     * 头像
+     */
+    private String image;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 用户会员等级,见表c_userlevel或枚举UserLevel【V6.2.0版本已废弃】
+     */
+    private Integer userLevelID;
+
+    /**
+     * 名称(机构名称,供应商的公司名称)
+     */
+    private String name;
+
+    /**
+     * 昵称【V6.2.0版本已废弃】
+     */
+    private String nick;
+
+    /**
+     * 性别【V2021已废弃】
+     */
+    private String sex;
+
+    /**
+     * 见枚举UserType(1供应商,2协销经理,32协销,3会员机构,4普通机构)
+     */
+    private Integer registerUserTypeID;
+
+    /**
+     * 所属企业用户对应UserID【V6.2.0版本已废弃】
+     */
+    private Integer companyUserID;
+
+    /**
+     * 微信openID【V6.2.0版本已废弃】
+     */
+    private String openID;
+
+    /**
+     * 是否是供应商,1是 空或0否【V6.2.0版本已废弃】
+     */
+    private String manufacturerFlag;
+
+    /**
+     * 供应商状态, 3待审核, 90已上线,91已下线,92审核不通过
+     */
+    private Integer manufacturerStatus;
+
+    /**
+     * 供应商Id
+     */
+    private Integer shopID;
+
+    /**
+     * 是否创客,1是 空或0否【V6.2.0版本已废弃】
+     */
+    private String serviceProviderFlag;
+
+    /**
+     * 是否会所,1是 空或0否【V6.2.0版本已废弃】
+     */
+    private String clubFlag;
+
+    /**
+     * 达人标志【V6.2.0版本已废弃】
+     */
+    private String masterFlag;
+
+    /**
+     * 【V6.2.0版本已废弃】
+     */
+    private String normalFlag;
+
+    /**
+     * 审核状态
+     */
+    private String auditStatus;
+
+    /**
+     * 审核时间
+     */
+    private String auditTime;
+
+    /**
+     * 审核备注
+     */
+    private String auditNote;
+
+    /**
+     * 注册时间
+     */
+    private String registerTime;
+
+    /**
+     * 注册ip
+     */
+    private String registerIP;
+
+    /**
+     * 登录时间
+     */
+    private String loginTime;
+
+    /**
+     * 登录ip
+     */
+    private String loginIP;
+
+    /**
+     * 用户状态,1正常,0冻结
+     */
+    private String validFlag;
+
+    /**
+     * 【V6.2.0版本已废弃】
+     */
+    private String emailCheckFlag;
+
+    /**
+     * 【V6.2.0版本已废弃】
+     */
+    private String mobileCheckFlag;
+
+    /**
+     * 会所状态,见表c_clubstatus或枚举ClubStatus
+     */
+    private Integer clubStatus;
+
+    /**
+     * 会所Id
+     */
+    private Integer clubID;
+
+    /**
+     * 同意协议标志
+     */
+    private String agreeFlag;
+
+    /**
+     * 【已废弃】
+     */
+    private String activationCode;
+
+    /**
+     * 【已废弃】
+     */
+    private String activationDate;
+
+    /**
+     * 创客状态
+     */
+    private Integer serviceProviderStatus;
+
+    /**
+     * 创客Id
+     */
+    private Integer serviceProviderID;
+
+    /**
+     * 【已废弃】达人状态
+     */
+    private Integer masterStatus;
+
+    /**
+     * 【已废弃】达人ID
+     */
+    private Integer masterID;
+
+    /**
+     * 账户余额
+     */
+    private BigDecimal userMoney;
+
+    /**
+     * 账户实际可用余额(提交订单未支付的被抵扣后的余额)
+     */
+    private BigDecimal ableUserMoney;
+
+    /**
+     * 积分【V6.2.0版本已废弃】
+     */
+    private Integer point;
+
+    /**
+     * 开通ERP标志【V6.2.0版本已废弃】
+     */
+    private String shopERPFlag;
+
+    /**
+     * 邀请人Id【V6.2.0版本已废弃】
+     */
+    private Integer fromUserID;
+
+    /**
+     * 邀请人名称【V6.2.0版本已废弃】
+     */
+    private String fromUserName;
+
+    /**
+     * 退出时间
+     */
+    private String logoffTime;
+
+    private String appKey;
+
+    private String appSecret;
+
+    /**
+     * 【已废弃】
+     */
+    private String sampleFlag;
+
+    /**
+     * 扫描标志(4 CRM拉上来的会所) 0待扫描 1 已扫描 2已上线
+     */
+    private Integer scanFlag;
+
+    /**
+     * 【已废弃】
+     */
+    private Integer sysroleid;
+
+    /**
+     * 【已废弃】
+     */
+    private String gender;
+
+    /**
+     * 年龄【V2021已废弃】
+     */
+    private Integer age;
+
+    /**
+     * 【V2021已废弃】
+     */
+    private String salerbuyer;
+
+    /**
+     * 【V2021已废弃】
+     */
+    private String position;
+
+    /**
+     * 【V2021已废弃】
+     */
+    private String skill;
+
+    /**
+     * 【V2021已废弃】
+     */
+    private BigDecimal workage;
+
+    /**
+     * 微信号【V2021已废弃】
+     */
+    private String wechat;
+
+    /**
+     * QQ号【V2021已废弃】
+     */
+    private String qq;
+
+    /**
+     * 短信是否发送成功【V2021已废弃】
+     */
+    private String smsFlag;
+
+    /**
+     * 采美豆数量【V2021已废弃】
+     */
+    private Integer userBeans;
+
+    /**
+     * 【已废弃】平台商标志位0非平台商 1平台商
+     */
+    private Integer privateShopFlag;
+
+    /**
+     * 【已废弃】平台会所标志位0非平台会所 1平台会所
+     */
+    private Integer privateClubFlag;
+
+    /**
+     * 是否创客授权【V2021已废弃】
+     */
+    private Integer isMeiDaoAuthorized;
+
+    /**
+     * 是否已经引导过(供应商首次登陆操作引导)
+     */
+    private Integer guideFlag;
+
+    private Integer loginFailTime;
+
+    /**
+     * 用户申请加入企业的时间【V2021已废弃】
+     */
+    private String applyTime;
+
+    private String tipStatus;
+
+    /**
+     * 企业账号由哪一个用户升级而来,对应一个userID【V6.2.0版本已废弃】
+     */
+    private Integer upgradeBy;
+
+    /**
+     * 小程序openId【V6.2.0版本已废弃】
+     */
+    private String miniProgramOpenId;
+
+    /**
+     * 小程序用户Id【V6.2.0版本已废弃】
+     */
+    private String miniProgramId;
+
+    private static final long serialVersionUID = 1L;
+}

+ 51 - 0
src/main/java/com/caimei/model/vo/AddressInfoVo.java

@@ -0,0 +1,51 @@
+package com.caimei.model.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * address
+ *
+ * @author
+ */
+@Data
+public class AddressInfoVo {
+
+  /**
+   * 收货人
+   */
+  @ApiModelProperty("收货人")
+  private String receiveMan;
+
+  /**
+   * 地址
+   */
+  @ApiModelProperty("地址")
+  private String addressDetail;
+
+  /**
+   * 手机
+   */
+  @ApiModelProperty("手机")
+  private String mobile;
+
+
+  /**
+   * 区名称
+   */
+  private String townName;
+
+  /**
+   * 市名称
+   */
+  private String cityName;
+
+  /**
+   * 县名称
+   */
+  private String provinceName;
+
+  private static final long serialVersionUID = 1L;
+}

+ 93 - 0
src/main/java/com/caimei/model/vo/AddressVo.java

@@ -0,0 +1,93 @@
+package com.caimei.model.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * address
+ *
+ * @author
+ */
+@Data
+public class AddressVo implements Serializable {
+    /**
+     * 用户地址ID
+     */
+    @ApiModelProperty("用户地址ID")
+    private Integer addressId;
+
+    /**
+     * 用户ID
+     */
+    @ApiModelProperty("用户ID")
+    private Integer userId;
+
+    /**
+     * 收货人
+     */
+    @ApiModelProperty("收货人")
+    private String shouHuoRen;
+
+    /**
+     * 区ID
+     */
+    @ApiModelProperty("区ID")
+    private Integer townId;
+
+    /**
+     * 地址
+     */
+    @ApiModelProperty("地址")
+    private String address;
+
+    /**
+     * 邮编
+     */
+    private String postalCode;
+
+    /**
+     * 电话
+     */
+    private String phone;
+
+    /**
+     * 手机
+     */
+    @ApiModelProperty("手机")
+    private String mobile;
+
+    /**
+     * 是否默认收货地址(0 不是默认,1 默认)
+     */
+    @ApiModelProperty("是否默认收货地址(0 不是默认,1 默认)")
+    private String defaultFlag;
+
+    /**
+     * 市id
+     */
+    private Integer cityId;
+
+    /**
+     * 县id
+     */
+    private Integer provinceId;
+
+    /**
+     * 区名称
+     */
+    private String townName;
+
+    /**
+     * 市名称
+     */
+    private String cityName;
+
+    /**
+     * 县名称
+     */
+    private String provinceName;
+
+    private static final long serialVersionUID = 1L;
+}

+ 55 - 0
src/main/java/com/caimei/model/vo/CmOrderVo.java

@@ -0,0 +1,55 @@
+package com.caimei.model.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2020/3/18
+ */
+@Data
+public class CmOrderVo{
+    /**
+     * 0待确认,11待收待发,12待收部发,13待收全发,21部收待发,22部收部发,23部收全发,31已收待发,32已收部发,33已收全发,4交易完成,5订单完成,6已关闭,7交易全退
+     */
+    private String status;
+
+    /**
+     * 退货退款类型:1部分退、2全部退
+     */
+    private String refundType;
+
+    /**
+     * 应付金额
+     */
+    private BigDecimal payableAmount;
+
+    /**
+     * 付款总金额
+     */
+    private BigDecimal receiptAmount;
+
+    /**
+     * 待付总金额
+     */
+    private BigDecimal pendingPayments;
+
+    /**
+     * 退款总金额
+     */
+    private BigDecimal returnedPurchaseFee;
+
+    /**
+     * 免邮标志  运费:-1到付,0包邮,1需要运费
+     */
+    private String freePostFlag;
+
+    /**
+     * 0包邮/到付,大于0具体金额
+     */
+    private BigDecimal freight;
+
+}

+ 22 - 0
src/main/java/com/caimei/model/vo/DiscernReceiptVo.java

@@ -0,0 +1,22 @@
+package com.caimei.model.vo;
+
+import com.caimei.model.po.CmDiscernReceiptPo;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2020\3\19 0019
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class DiscernReceiptVo extends CmDiscernReceiptPo {
+    /**
+     * 单次收款金额
+     */
+    private BigDecimal associateAmount;
+}

+ 73 - 0
src/main/java/com/caimei/model/vo/DisplayOrderProductVo.java

@@ -0,0 +1,73 @@
+package com.caimei.model.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * @author Aslee
+ */
+@Data
+public class DisplayOrderProductVo {
+
+    /**
+     * 商品Id
+     */
+    private String productId;
+
+    /**
+     * 商品名称
+     */
+    private String productName;
+
+    /**
+     * 供应商名称
+     */
+    private String shopName;
+
+    /**
+     * 商品图片
+     */
+    private String image;
+
+    /**
+     * 机构价
+     */
+    private BigDecimal price;
+
+    /**
+     * 规格
+     */
+    private String unit;
+
+    /**
+     * 商品数量
+     */
+    private Integer productNum;
+
+    /**
+     * 后台设置该商品税率
+     */
+    private BigDecimal taxRate;
+
+    /**
+     * 已发货数量
+     */
+    private Integer shipmentsNum;
+
+    /**
+     * 已退货数量
+     */
+    private Integer returnedNum;
+
+    /**
+     * 已取消发货数量
+     */
+    private Integer actualCancelNum;
+
+    /**
+     * 商品前台展示单价是否含税,1不含税,2含税,3其他
+     */
+    private String includedTaxFlag;
+}

+ 38 - 0
src/main/java/com/caimei/model/vo/LadderPriceVo.java

@@ -0,0 +1,38 @@
+package com.caimei.model.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Aslee
+ */
+@Data
+public class LadderPriceVo {
+    private Integer id;
+
+    /**
+     * 商品id
+     */
+    private Integer productId;
+
+    /**
+     * 第几阶梯
+     */
+    private Integer ladderNum;
+
+    /**
+     * 购买数量
+     */
+    private Integer buyNum;
+
+    /**
+     * 购买价格
+     */
+    private BigDecimal buyPrice;
+
+    /**
+     * 阶梯价格数量区间显示
+     */
+    private String buyNumRangeShow;
+}

+ 54 - 0
src/main/java/com/caimei/model/vo/OrderProductVo.java

@@ -0,0 +1,54 @@
+package com.caimei.model.vo;
+
+import com.caimei.model.po.CmOrderProductPo;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2020\3\19 0019
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class OrderProductVo extends CmOrderProductPo {
+    /**
+     * 已发货数量
+     */
+    private Integer shipmentsNum;
+
+    /**
+     * 已退货数量
+     */
+    private Integer returnedNum;
+
+    /**
+     * 已取消发货数量
+     */
+    private Integer actualCancelNum;
+
+    /**
+     * 内部商品名称
+     */
+    private String aliasName;
+
+    /**
+     * 商品的类别:1正常商品(默认),2二手商品
+     */
+    private String productCategory;
+
+    /**
+     * 二手商品分类,1二手仪器,2临期产品,3其他
+     */
+    private String secondHandType;
+
+    /**
+     * 商品前台展示单价是否含税,1不含税,2含税,3其他
+     */
+    private String includedTaxFlag;
+    /**
+     * api组织商品id
+     */
+    private Integer apiOrganizeProductId;
+}

+ 69 - 0
src/main/java/com/caimei/model/vo/OrderVo.java

@@ -0,0 +1,69 @@
+package com.caimei.model.vo;
+
+import com.caimei.model.po.CmOrderPo;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2020/3/18
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class OrderVo extends CmOrderPo {
+
+    /**
+     * 订单状态:0全部,1待付款,2待发货,3已发货,4退货款
+     */
+    private Integer orderState;
+
+    /**
+     * 订单标识:#订单号#
+     */
+    private String orderMark;
+
+    /**
+     * 付款总金额
+     */
+    private BigDecimal receiptAmount;
+
+    /**
+     * 待付总金额
+     */
+    private BigDecimal pendingPayments;
+
+    /**
+     * 退款总金额
+     */
+    private BigDecimal returnedPurchaseFee;
+
+    /**
+     * 总税费
+     */
+    private BigDecimal ExpensesOfTaxation;
+
+    /**
+     * 机构名称
+     */
+    private String clubName;
+
+    /**
+     * 订单内是否包含确定能否开发票的商品
+     */
+    private boolean invoiceStatus = false;
+
+    /**
+     * 支付按钮是否消失,true消失
+     */
+    private boolean payButton = false;
+
+    /**
+     * 是否包含充值商品
+     */
+    private boolean rechargeGoods = false;
+}

+ 78 - 0
src/main/java/com/caimei/model/vo/ProductDetailVo.java

@@ -0,0 +1,78 @@
+package com.caimei.model.vo;
+
+import com.caimei.model.po.ProductDetailInfoPo;
+import com.caimei.model.po.ProductImagePo;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/3/23
+ */
+@Data
+public class ProductDetailVo {
+
+    /**
+     * 商品Id
+     */
+    private String productId;
+
+    /**
+     * 商品名称
+     */
+    private String productName;
+
+    /**
+     * 供应商名称
+     */
+    private String shopName;
+
+    /**
+     * 商品图片
+     */
+    private String image;
+
+    /**
+     * 机构价
+     */
+    private BigDecimal price;
+
+    /**
+     * 规格
+     */
+    private String unit;
+
+    /**
+     * 起订量
+     */
+    private Integer minBuyNumber;
+
+    /**
+     * 启用阶梯价格标识 0否 1是
+     */
+    private Integer ladderPriceFlag;
+
+    /**
+     * 阶梯价格集合
+     */
+    private List<LadderPriceVo> ladderPriceList;
+
+    /**
+     * 品牌名称
+     */
+    private String brandName;
+
+    /**
+     * 商品图片
+     */
+    private List<ProductImagePo> imageList;
+
+    /**
+     * 商品详情
+     */
+    private ProductDetailInfoPo productDetail;
+}

+ 66 - 0
src/main/java/com/caimei/model/vo/ProductListVo.java

@@ -0,0 +1,66 @@
+package com.caimei.model.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/3/23
+ */
+@Data
+public class ProductListVo {
+
+    /**
+     * 商品Id
+     */
+    private String productId;
+
+    /**
+     * 商品名称
+     */
+    private String productName;
+
+    /**
+     * 供应商名称
+     */
+    private String shopName;
+
+    /**
+     * 商品图片
+     */
+    private String image;
+
+    /**
+     * 机构价
+     */
+    private BigDecimal price;
+
+    /**
+     * 规格
+     */
+    private String unit;
+
+    /**
+     * 起订量
+     */
+    private Integer minBuyNumber;
+
+    /**
+     * 启用阶梯价格标识 0否 1是
+     */
+    private Integer ladderPriceFlag;
+
+    /**
+     * 阶梯价格集合
+     */
+    private List<LadderPriceVo> ladderPriceList;
+
+    /**
+     * 品牌名称
+     */
+    private String brandName;
+}

+ 168 - 0
src/main/java/com/caimei/model/vo/ProductVo.java

@@ -0,0 +1,168 @@
+package com.caimei.model.vo;
+
+import com.caimei.model.po.ProductDetailInfoPo;
+import com.caimei.model.po.ProductImagePo;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/3/23
+ */
+@Data
+public class ProductVo {
+
+    /**
+     * 商品Id
+     */
+    private Integer productId;
+
+    /**
+     * 原采美商品Id
+     */
+    private Integer originalProductId;
+
+    /**
+     * 商品名称
+     */
+    private String productName;
+
+    /**
+     * 商品图片
+     */
+    private String mainImage;
+
+    /**
+     * 供应商名称
+     */
+    private String shopName;
+
+    /**
+     * 机构价
+     */
+    private BigDecimal price;
+
+    /**
+     * 规格
+     */
+    private String unit;
+
+    /**
+     * 起订量
+     */
+    private Integer minBuyNumber;
+
+    /**
+     * 启用阶梯价格标识 0否 1是
+     */
+    private Integer ladderPriceFlag;
+
+    /**
+     * 是否含税   0不含税,1含税,2未知
+     */
+    private Integer includedTax;
+
+    /**
+     * 发票类型(基于是否含税基础)   1增值税票,2普通票, 3不能开票
+     */
+    private Integer invoiceType;
+
+    /**
+     * 开票税点(基于不含税基础) :增值税默认13%,普通票6%取值范围[0-100]
+     */
+    private BigDecimal clubTaxPoint;
+
+    /**
+     * 展示价格
+     */
+    private BigDecimal retailPrice;
+
+    /**
+     * 商品状态:0已下架,1已上架
+     */
+    private Integer status;
+
+    /**
+     * 商品标签用英文逗号隔开,中文逗号或其它一律不作切割
+     */
+    private String tags;
+
+    /**
+     * 阶梯价格集合
+     */
+    private List<LadderPriceVo> ladderPriceList;
+
+    /**
+     * 商品是否处于活动状态:1是,空或0不是[活动商品和actFlag含义不同]
+     */
+    private Integer actStatus;
+
+    /**
+     * 标签数组
+     */
+    private String[] tagsList;
+
+    /**
+     * 商品图片
+     */
+    private List<ProductImagePo> imageList;
+
+    /**
+     * 商品详情
+     */
+    private ProductDetailInfoPo productDetail;
+
+    /**
+     * 机构用户价格等级(范围1-5)【V6.2.0版本已废弃-根据价格范围显示等级】
+     */
+    private String priceGrade;
+
+    /**
+     * 一级分类id
+     */
+    private Integer bigTypeId;
+
+    /**
+     * 二级分类id
+     */
+    private Integer smallTypeId;
+
+    /**
+     * 三级分类Id
+     */
+    private Integer tinyTypeId;
+
+    /**
+     * 所在分类名称
+     */
+    private String typeName;
+
+    /**
+     * 品牌Id
+     */
+    private Integer brandId;
+
+    /**
+     * 品牌名称
+     */
+    private String brandName;
+
+    /**
+     * 商品编码
+     */
+    private String productCode;
+
+    /**
+     * 库存
+     */
+    private Integer stock;
+
+    /**
+     * 商品备注
+     */
+    private String productRemark;
+}

+ 45 - 0
src/main/java/com/caimei/service/OrderService.java

@@ -0,0 +1,45 @@
+package com.caimei.service;
+
+import com.caimei.model.ResponseJson;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Map;
+
+/**
+ * @author Aslee
+ */
+public interface OrderService {
+    /**
+     * 订单提交
+     *
+     * @param cmAccount
+     * @param data
+     * @return
+     */
+    ResponseJson orderSubmit(String cmAccount, String data);
+
+    /**
+     * 订单详情
+     * @param cmAccount
+     * @param data
+     * @return
+     */
+    ResponseJson<Map<String,Object>> orderDetail(String cmAccount, String data);
+
+    /**
+     * 取消订单
+     * @param cmAccount
+     * @param data
+     * @return
+     */
+    ResponseJson orderCancel(String cmAccount, String data);
+
+    /**
+     * 测试通知回调
+     * @param cmAccount
+     * @param data
+     * @return
+     */
+    ResponseJson payCallBack(String cmAccount, String data);
+}

+ 29 - 0
src/main/java/com/caimei/service/ProductService.java

@@ -0,0 +1,29 @@
+package com.caimei.service;
+
+import com.caimei.model.ResponseJson;
+import com.caimei.model.vo.ProductDetailVo;
+import com.caimei.model.vo.ProductListVo;
+
+import java.util.List;
+
+/**
+ * @author Aslee
+ */
+public interface ProductService {
+    /**
+     * 商品列表
+     *
+     * @param cmAccount
+     * @param data
+     * @return
+     */
+    ResponseJson<List<ProductListVo>> productList(String cmAccount, String data);
+
+    /**
+     * 商品详情
+     * @param cmAccount
+     * @param data
+     * @return
+     */
+    ResponseJson<ProductDetailVo> productDetail(String cmAccount, String data);
+}

+ 1145 - 0
src/main/java/com/caimei/service/impl/OrderServiceImpl.java

@@ -0,0 +1,1145 @@
+package com.caimei.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.caimei.mapper.OrderMapper;
+import com.caimei.mapper.OrganizeMapper;
+import com.caimei.mapper.ProductMapper;
+import com.caimei.model.ResponseJson;
+import com.caimei.model.enumerate.ReceivablesType;
+import com.caimei.model.po.*;
+import com.caimei.model.vo.*;
+import com.caimei.service.OrderService;
+import com.caimei.utils.*;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * @author Aslee
+ */
+@Slf4j
+@Service
+public class OrderServiceImpl implements OrderService {
+    @Resource
+    private OrderMapper orderMapper;
+    @Resource
+    private OrganizeMapper organizeMapper;
+    @Resource
+    private ProductMapper productMapper;
+
+    @Value("${caimei.oldapi}")
+    private String domain;
+
+    @Transactional
+    @Override
+    public ResponseJson orderSubmit(String cmAccount, String data) {
+        // 获取组织信息
+        CmApiOrganizePo organizePo = organizeMapper.getOrganizeByCmAccount(cmAccount);
+        if (null == organizePo) {
+            return ResponseJson.error("参数异常,用户不存在");
+        }
+        // 获得用户Id
+        Integer userId = organizePo.getUserId();
+        JSONObject orderInfo = null;
+        try {
+            // 使用组织对应的公钥解密,获得订单数据
+            orderInfo = KeyUtils.decryptDataPublic(data, organizePo.getPublicKey());
+            // 私钥验签
+            String preSign = orderInfo.getString("sign");
+            orderInfo.remove("sign");
+            String sufSign = KeyUtils.buildSign(orderInfo, organizePo.getPrivateKey());
+            if (!preSign.equals(sufSign)) {
+                return ResponseJson.error("验签失败");
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return ResponseJson.error("解密失败");
+        }
+        String apiOrganizeOrderId;
+        Map<String, Object> addressInfo;
+        Map<String, Object> productInfo;
+        Map<String, Object> payInfo;
+        Map<String, Object> invoiceInfo;
+        String notifyUrl;
+        try {
+            addressInfo = orderInfo.getJSONObject("addressInfo");
+            if (null == addressInfo) {
+                return ResponseJson.error("地址数据异常");
+            }
+            // 组织订单Id,由组织自行生成,必须唯一
+            apiOrganizeOrderId = orderInfo.getString("orderId");
+            // 验证组织订单Id是否唯一
+            Integer countByOrderId = orderMapper.getCountByOrderId(userId, apiOrganizeOrderId);
+            if (null != countByOrderId && countByOrderId > 0) {
+                return ResponseJson.error("订单Id已存在,请勿重复提交");
+            }
+            productInfo = orderInfo.getJSONObject("productInfo");
+            if (null == productInfo) {
+                return ResponseJson.error("订单商品数据异常");
+            }
+            payInfo = orderInfo.getJSONObject("payInfo");
+            if (null == payInfo) {
+                return ResponseJson.error("订单金额数据异常");
+            }
+            invoiceInfo = orderInfo.getJSONObject("invoiceInfo");
+            if (null == invoiceInfo) {
+                return ResponseJson.error("订单发票数据异常");
+            }
+            notifyUrl = orderInfo.getString("notifyUrl");
+            if (StringUtils.isNotEmpty(notifyUrl) && !notifyUrl.equals(organizePo.getNotifyUrl())) {
+                //更新回调地址
+                orderMapper.updateNotifyUrl(organizePo.getOrganizeId(), notifyUrl);
+            }
+        } catch (Exception e) {
+            return ResponseJson.error("数据异常");
+        }
+        log.info("******************** 提交订单逻辑处理 start *******************");
+        //机构用户
+        UserPo user = orderMapper.getUserByUserId(userId);
+        if (null == user) {
+            return ResponseJson.error("用户信息异常");
+        }
+        // 商品总数量
+        Integer productCount = 0;
+        // 赠品数量
+        Integer presentCount = 0;
+        //促销赠品数量
+        Integer promotionalGiftsCount = 0;
+        // 商品总金额 (商品单价乘以数量,再加上税费[默认0])
+        BigDecimal productTotalFee = BigDecimal.ZERO;
+        // 小计金额(商品折后单价乘以数量,再加上税费[默认0])
+        BigDecimal orderTotalFee = BigDecimal.ZERO;
+        // 订单总额(小计金额减去经理折扣后,再加上运费[默认0])
+        BigDecimal payTotalFee = BigDecimal.ZERO;
+        // 真实支付金额(订单总额减去抵扣的账户余额)
+        BigDecimal payableAmount = BigDecimal.ZERO;
+        // 运费
+        if (null == payInfo.get("freePostFlag") || null == payInfo.get("freight")) {
+            return ResponseJson.error("运费数据异常");
+        }
+        Integer freePostFlag = (Integer) payInfo.get("freePostFlag");
+        BigDecimal freight = new BigDecimal(payInfo.get("freight").toString());
+        /*
+         * 发票信息获取
+         */
+        boolean invoiceFlag = false;
+        BpOrderInvoicePo invoice = new BpOrderInvoicePo();
+        Integer invoiceType = (Integer) invoiceInfo.get("type");
+        if (null == invoiceType) {
+            return ResponseJson.error("发票类型不能为空");
+        } else {
+            invoice.setType(invoiceType.longValue());
+            if (0 != invoiceType) {
+                // 发票类型 0不开发票 1普通发票 2增值税发票
+                invoiceFlag = true;
+                if (setInvoiceParam(invoiceInfo, invoice, invoiceType)) {
+                    return ResponseJson.error("发票信息不完整");
+                }
+            }
+        }
+        // 获取地址信息
+        String provinceName = (String) addressInfo.get("provinceName");
+        String cityName = (String) addressInfo.get("cityName");
+        String townName = (String) addressInfo.get("townName");
+        String receiveMan = (String) addressInfo.get("receiveMan");
+        String mobile = (String) addressInfo.get("mobile");
+        String addressDetail = (String) addressInfo.get("addressDetail");
+        if (StringUtils.isEmpty(provinceName) || StringUtils.isEmpty(cityName) || StringUtils.isEmpty(townName) || StringUtils.isEmpty(receiveMan) || StringUtils.isEmpty(mobile)) {
+            return ResponseJson.error("地址信息不完整");
+        }
+        Integer provinceId = orderMapper.getProvinceId(provinceName);
+        Integer cityId = orderMapper.getCityId(cityName);
+        Integer townId = orderMapper.getTownId(townName);
+        if (null == provinceId || null == cityId || null == townId) {
+            return ResponseJson.error("地址信息异常");
+        }
+        // 验证运费是否正确
+        if (1 == freePostFlag) {
+            if (19 != provinceId) {
+                return ResponseJson.error("广东省外地址只能到付");
+            } else if (202 != cityId) {
+                if (0 != freight.compareTo(new BigDecimal(15))) {
+                    return ResponseJson.error("深圳市外运费应为15元");
+                }
+            } else if (0 != freight.compareTo(new BigDecimal(10))) {
+                return ResponseJson.error("深圳室内运费应为10元");
+            }
+        } else if (0 != freight.compareTo(BigDecimal.ZERO)) {
+            return ResponseJson.error("运费应为0元");
+        }
+        /*
+         * 初始化主订单参数
+         */
+        CmOrderPo order = new CmOrderPo();
+        String curDateStr = (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date());
+        // 订单号
+        String orderNo = OrderNoUtils.getOrderNo("D");
+        order.setOrderNo(orderNo);
+        order.setApiOrganizeOrderId(apiOrganizeOrderId);
+        // 运营人员下单
+        order.setBuyUserID(user.getUserID());
+        order.setOrderType(1);
+        order.setOrderSubmitType(2);
+        order.setConfirmFlag("2");
+        order.setUserID(user.getUserID().longValue());
+        // 机构ID
+        order.setClubID(user.getClubID().longValue());
+        // 订单来源
+        order.setOrderSource("7");
+        order.setOrganizeID(0);
+        order.setUpdateDate(curDateStr);
+        order.setPayFlag("0");
+        order.setCooFreeFlag("0");
+        order.setCooFreeAmount(BigDecimal.ZERO);
+        order.setCooFreeRate(0);
+        order.setOnlinePayFlag("0");
+        order.setPreferential(BigDecimal.ZERO);
+        order.setDiscountFee(BigDecimal.ZERO);
+        // 订单提交时间
+        order.setOrderTime(curDateStr);
+        // 默认订单可以拆分
+        order.setSplitFlag("1");
+        // 发票类型
+        order.setInvoiceFlag(invoiceType.toString());
+        order.setReceiptStatus("1");
+        order.setPayStatus("1");
+        order.setZeroCostFlag(0);
+        order.setSendOutStatus("1");
+        order.setRefundType("0");
+        // 是否包含活动商品(受订单未支付自动关闭时间影响)  0 否 1 是
+        order.setHasActProduct("0");
+        // 订单状态 0 有效  其它无效
+        order.setDelFlag("0");
+        // 是否确认付款供应商
+        order.setAffirmPaymentFlag("0");
+        /*
+            订单商品
+         */
+        List<CmOrderProductPo> orderProductList = new ArrayList<>();
+        // 收集供应商ID列表
+        List<Integer> shopIdList = new ArrayList<>();
+        for (Map.Entry<String, Object> product : productInfo.entrySet()) {
+            String productId = product.getKey();
+            Integer productNum = (Integer)product.getValue();
+            // 统计商品数量
+            productCount += productNum;
+            // 获取商品信息
+            CmApiOrganizeProductPo organizeProduct = productMapper.getProductByProductId(productId);
+            if (null == organizeProduct) {
+                return ResponseJson.error("订单商品数据异常");
+            }
+            if (null == productNum || productNum == 0) {
+                return ResponseJson.error("商品购买数量异常");
+            }
+            // 获取商品购买价格(活动价格>>>阶梯价格>>>复购价格库>>>商品原始价)
+            BigDecimal productPrice = organizeProduct.getPrice();
+            // 成本价
+            BigDecimal costPrice = BigDecimal.ZERO;
+            // 机构税费(单)
+            BigDecimal addedValueTax = new BigDecimal(0);
+            int priceType = 0;
+            // 活动状态
+            organizeProduct.setActStatus(0);
+            if (1 == organizeProduct.getLadderPriceFlag()) {
+                // 启用了阶梯价格
+                List<LadderPriceVo> ladderPriceList = productMapper.getLadderPriceByProductId(organizeProduct.getId());
+                // 判断阶梯价格的购买数量校验
+                long minBuyNumber = null != ladderPriceList.get(0) ? ladderPriceList.get(0).getBuyNum() : 0L;
+                if (productNum < minBuyNumber) {
+                    return ResponseJson.error("商品购买量低于最小起订量");
+                }
+                //根据商品购买数量获取商品对应阶梯价格
+                for (LadderPriceVo ladderPrice : ladderPriceList) {
+                    if (productNum >= ladderPrice.getBuyNum()) {
+                        productPrice = ladderPrice.getBuyPrice();
+                    }
+                }
+                organizeProduct.setActStatus(2);
+                priceType = 2;
+            }
+            //不含税可开票商品计算税费
+            boolean addTaxFlag = 0 == organizeProduct.getIncludedTax() && (1 == organizeProduct.getInvoiceType() || 2 == organizeProduct.getInvoiceType());
+            if (addTaxFlag) {
+                addedValueTax = MathUtil.div(MathUtil.mul(productPrice, organizeProduct.getClubTaxPoint()), BigDecimal.valueOf(100));
+                productPrice = MathUtil.add(productPrice, addedValueTax);
+            }
+            if (MathUtil.compare(productPrice, BigDecimal.ZERO) == 0) {
+                return ResponseJson.error("商品购买价格不能为0");
+            }
+            // 单个商品的金额
+            BigDecimal productFee = MathUtil.mul(productPrice, productNum);
+            // 统计商品总金额
+            productTotalFee = MathUtil.add(productTotalFee, productFee);
+            // 判断是否选中固定成本价
+            if (MathUtil.compare(organizeProduct.getCostPrice(), 0) > 0 && 1 == organizeProduct.getCostType()) {
+                costPrice = organizeProduct.getCostPrice();
+            }
+            // 判断是否选中比例成本价
+            if (MathUtil.compare(organizeProduct.getCostProportional(), 0) > 0 && 2 == organizeProduct.getCostType()) {
+                // 通过售价*比例得到成本价
+                costPrice = BigDecimal.valueOf(MathUtil.div(MathUtil.mul(productPrice, organizeProduct.getCostProportional()), 100).floatValue());
+            }
+            organizeProduct.setCostPrice(costPrice);
+            /*
+             * 整理订单商品数据
+             */
+            CmOrderProductPo orderProduct = setOrderProduct(productNum, organizeProduct, productPrice, priceType, 1, addedValueTax);
+            // 加入订单商品列表
+            orderProductList.add(orderProduct);
+            // 保存供应商id
+            if (!shopIdList.contains(orderProduct.getShopID().intValue())) {
+                shopIdList.add(orderProduct.getShopID().intValue());
+            }
+        }
+        // 设置是否是二手订单
+        order.setSecondHandOrderFlag("0");
+        order.setPromotionFullReduction(BigDecimal.ZERO);
+        // 商品总数量
+        order.setProductCount(productCount);
+        // 赠品数量
+        order.setPresentCount(0);
+        //促销赠品数量
+        order.setPromotionalGiftsCount(0);
+        // 0包邮 -1到付 1 有运费
+        order.setFreePostFlag(freePostFlag.toString());
+        order.setFreight(freight);
+        // 商品总额
+        order.setProductTotalFee(productTotalFee);
+        // 订单总额(商品金额+运费)
+        if (1 == freePostFlag) {
+            // 机构用户 计算商品运费
+            Double freightFee = computedPostageFee(provinceId, cityId);
+            freight = BigDecimal.valueOf(freightFee);
+            order.setFreight(freight);
+            payTotalFee = MathUtil.add(productTotalFee, freight);
+        } else {
+            payTotalFee = productTotalFee;
+        }
+        orderTotalFee = productTotalFee;
+        order.setOrderTotalFee(orderTotalFee);
+        order.setPayTotalFee(payTotalFee);
+        payableAmount = payTotalFee;
+
+        // 订单状态
+        order.setStatus("11");
+        order.setConfirmTime(curDateStr);
+
+        // 余额支付金额
+        order.setBalancePayFee(BigDecimal.ZERO);
+        // 实际支付金额(商品金额+运费-余额抵扣)
+        order.setPayableAmount(payableAmount);
+        // 售后条款
+        order.setClauseID(1L);
+        order.setClauseName("无条款");
+        // 是否返佣订单
+        order.setRebateFlag("0");
+        // 判断前端传入orderShouldPayFee订单应付金额,和后台计算应付金额对比
+        BigDecimal orderShouldPayFee = new BigDecimal(payInfo.get("orderShouldPayFee").toString());
+        double v = MathUtil.sub(payableAmount, orderShouldPayFee).doubleValue();
+        log.info(">>>>>payableAmount:" + payableAmount + " ,orderShouldPayFee:" + orderShouldPayFee);
+        // 考虑前端计算不精确
+        if (v < -0.1d || v > 0.1d) {
+            // 设置手动回滚事务
+            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+            return ResponseJson.error("订单付款金额异常");
+        }
+
+        /*
+         * 保存主订单数据
+         */
+        orderMapper.insertOrder(order);
+        log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>新增主订单(insert[cm_order])orderId:" + order.getOrderID());
+
+        /*
+         * 设置订单商品订单号
+         */
+        for (CmOrderProductPo orderProduct : orderProductList) {
+            orderProduct.setOrderID(order.getOrderID());
+            orderProduct.setOrderNo(order.getOrderNo());
+        }
+        /*
+         * 整理 子订单信息
+         */
+        // 收集子订单供应商ID字符串
+        String shopOrderIds = "";
+        for (Integer shopId : shopIdList) {
+            // 初始化子订单信息
+            CmShopOrderPo shopOrder = saveShopOrder(order, orderProductList, shopId, "");
+            // 保存子订单号
+            shopOrderIds += (("".equals(shopOrderIds) ? "" : ",") + shopOrder.getShopOrderID());
+            // 设置订单商品子订单号
+            for (CmOrderProductPo orderProduct : orderProductList) {
+                if (shopId.longValue() == orderProduct.getShopID()) {
+                    orderProduct.setShopOrderID(shopOrder.getShopOrderID());
+                    orderProduct.setShopOrderNo(shopOrder.getShopOrderNo());
+                }
+            }
+        }
+        /*
+         * 保存订单商品
+         */
+        List<OrderProductLadderPricePo> orderProductLadderPriceList = new ArrayList<>();
+        for (CmOrderProductPo orderProduct : orderProductList) {
+            // 保存订单商品数据
+            orderMapper.insertOrderProduct(orderProduct);
+            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>保存订单商品(insert[cm_order_product])OrderProductID:" + orderProduct.getOrderProductID());
+            if ("1".equals(orderProduct.getLadderPriceFlag())) {
+                //使用阶梯价格的订单商品保存下单时的阶梯价格列表
+                List<LadderPriceVo> ladderPriceList = productMapper.findLadderPriceByProductId(orderProduct.getProductID());
+                ladderPriceList.forEach(ladderPriceVo -> {
+                    OrderProductLadderPricePo orderProductLadderPrice = new OrderProductLadderPricePo();
+                    orderProductLadderPrice.setOrderProductId(orderProduct.getOrderProductID());
+                    orderProductLadderPrice.setBuyNum(ladderPriceVo.getBuyNum());
+                    orderProductLadderPrice.setBuyPrice(ladderPriceVo.getBuyPrice());
+                    orderProductLadderPrice.setCreateDate(new Date());
+                    orderProductLadderPrice.setLadderNum(ladderPriceVo.getLadderNum());
+                    orderProductLadderPriceList.add(orderProductLadderPrice);
+                });
+            }
+        }
+        if (!CollectionUtils.isEmpty(orderProductLadderPriceList)) {
+            orderProductLadderPriceList.forEach(ladderPrice -> {
+                orderMapper.insertOrderProductLadderPrice(ladderPrice);
+            });
+        }
+        /*
+         * 设置邮费子订单
+         */
+        if ("1".equals(order.getFreePostFlag())) {
+            shopOrderIds = setPostFeeShopOrder(order, shopOrderIds, orderInfo.size());
+        }
+
+        // 更新主订单信息, 子订单ID:1000,1002
+        order.setShopOrderIDs(shopOrderIds);
+        orderMapper.updateOrder(order);
+
+        /*
+         * 保存 订单用户地址
+         */
+        //保存地址信息
+        BpOrderUserInfoPo userInfo = new BpOrderUserInfoPo();
+        userInfo.setOrderId(order.getOrderID());
+        userInfo.setClubId(user.getClubID().longValue());
+        userInfo.setUserId(user.getUserID().longValue());
+        userInfo.setName(user.getName() == null ? user.getUserName() : user.getName());
+        userInfo.setShouHuoRen(receiveMan);
+        userInfo.setMobile(mobile);
+        userInfo.setPostalCode(null);
+        userInfo.setPostalCode(null);
+        userInfo.setTownId(townId);
+        userInfo.setProvince(provinceName);
+        userInfo.setCity(cityName);
+        userInfo.setTown(townName);
+        userInfo.setAddress(addressDetail);
+        orderMapper.insertUserInfo(userInfo);
+        log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>保存订单用户地址(insert[bp_order_userinfo])orderId:" + order.getOrderID());
+
+
+        /*
+         * 保存 订单发票信息
+         */
+        if (invoiceFlag) {
+            // 开发票才保存
+            invoice.setOrderId(order.getOrderID());
+            // 查询是否存在老的增值税信息
+            BpOrderInvoicePo userInvoice = orderMapper.getOrderInvoice(order.getOrderID());
+            if (null != userInvoice) {
+                // 更新 发票信息
+                orderMapper.updateOrderInvoice(invoice);
+                log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>更新发票信息(update[bp_order_invoice])orderId:" + order.getOrderID());
+            } else {
+                //  保存 发票信息
+                orderMapper.insertOrderInvoice(invoice);
+                log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>新增发票信息(insert[bp_order_invoice])orderId:" + order.getOrderID());
+            }
+        }
+        log.info("******************** 提交订单逻辑处理 end *******************");
+        /*
+         * 构造返回参数
+         */
+        Map<String, String> info = new HashMap<>(5);
+        //组织订单id
+        info.put("orderId", apiOrganizeOrderId);
+        //真实需要付款金额
+        info.put("payableAmount", String.valueOf(order.getPayableAmount()));
+        return ResponseJson.success(info);
+    }
+
+
+    @Override
+    public ResponseJson<Map<String,Object>> orderDetail(String cmAccount, String data) {
+        // 获取组织信息
+        CmApiOrganizePo organizePo = organizeMapper.getOrganizeByCmAccount(cmAccount);
+        if (null == organizePo) {
+            return ResponseJson.error("参数异常,用户不存在", null);
+        }
+        // 获取用户id
+        Integer userId = organizePo.getUserId();
+        JSONObject orderInfo = null;
+        try {
+            // 使用组织对应的公钥解密,获得订单数据
+            orderInfo = KeyUtils.decryptDataPublic(data, organizePo.getPublicKey());
+            // 私钥验签
+            String preSign = orderInfo.getString("sign");
+            orderInfo.remove("sign");
+            String sufSign = KeyUtils.buildSign(orderInfo, organizePo.getPrivateKey());
+            if (!preSign.equals(sufSign)) {
+                return ResponseJson.error("验签失败", null);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return ResponseJson.error("解密失败", null);
+        }
+        String apiOrganizeOrderId = (String) orderInfo.get("orderId");
+        if (StringUtils.isEmpty(apiOrganizeOrderId)) {
+            return ResponseJson.error("参数异常,订单Id不能为空",null);
+        }
+        // 订单信息,运费
+        OrderVo order = orderMapper.getOrderInfo(userId, apiOrganizeOrderId);
+        if (null == order) {
+            return ResponseJson.error("该订单不存在", null);
+        }
+        // 收货地址
+        AddressInfoVo addressInfo = orderMapper.getAddressInfo(order.getOrderID().intValue());
+        // 收款列表
+        getDiscernReceipt(order);
+        CmOrderVo cmOrderVo = new CmOrderVo();
+        // 应付金额
+        cmOrderVo.setPayableAmount(order.getPayableAmount());
+        // 待付金额
+        cmOrderVo.setPendingPayments(order.getPendingPayments());
+        // 收发状态
+        cmOrderVo.setStatus(order.getStatus());
+        // 退款状态
+        cmOrderVo.setRefundType(order.getRefundType());
+        // 退款记录
+        List<CmReturnedPurchasePo> returnedPurchaseList = orderMapper.findReturnedPurchase(order.getOrderID());
+        if (returnedPurchaseList != null && returnedPurchaseList.size() > 0) {
+            BigDecimal returnedPurchaseFee = new BigDecimal(0);
+            for (CmReturnedPurchasePo returnedPurchase : returnedPurchaseList) {
+                returnedPurchaseFee = returnedPurchaseFee.add(returnedPurchase.getRefundFee());
+            }
+            //退款总金额
+            cmOrderVo.setReturnedPurchaseFee(returnedPurchaseFee);
+        }
+        // 运费信息
+        cmOrderVo.setFreePostFlag(order.getFreePostFlag());
+        cmOrderVo.setFreight(order.getFreight());
+        // 发票信息
+        BpOrderInvoicePo invoiceInfo = orderMapper.getOrderInvoice(order.getOrderID());
+        // 商品信息
+        List<OrderProductVo> dbProductList = productMapper.getOrderProduct(order.getOrderID());
+        List<DisplayOrderProductVo> orderProductList = new ArrayList<>();
+        DecimalFormat decimalFormat = new DecimalFormat("0000");
+        for (OrderProductVo orderProduct : dbProductList) {
+            DisplayOrderProductVo product = new DisplayOrderProductVo();
+            product.setProductId(decimalFormat.format(orderProduct.getApiOrganizeProductId()));
+            product.setImage(ImageUtils.getImageURL("product", orderProduct.getProductImage(), 0, domain));
+            product.setProductName(orderProduct.getName());
+            product.setShopName(orderProduct.getShopName());
+            product.setUnit(orderProduct.getProductUnit());
+            product.setPrice(orderProduct.getDiscountPrice());
+            product.setProductNum(orderProduct.getNum());
+            product.setTaxRate(orderProduct.getTaxRate());
+            //是否包含充值商品
+            /*if (OrderNoUtils.getRechargeProduct(orderProduct.getProductID())) {
+                order.setRechargeGoods(true);
+            }*/
+            //已发货数量
+            product.setShipmentsNum(orderProduct.getNum() + orderProduct.getPresentNum() - orderProduct.getNotOutStore());
+            //已退货数量
+            Integer returnedNum = orderMapper.returnedPurchase(orderProduct.getShopOrderID(), orderProduct.getProductID());
+            returnedNum = null != returnedNum ? returnedNum : 0;
+            product.setReturnedNum(returnedNum);
+            //已取消发货数量
+            Integer actualCancelNum = orderMapper.actualCancelNum(orderProduct.getShopOrderID(), orderProduct.getProductID());
+            actualCancelNum = null != actualCancelNum ? actualCancelNum : 0;
+            product.setActualCancelNum(actualCancelNum);
+            //判断商品价格是否含税
+            if ("1".equals(orderProduct.getIncludedTax()) || ("0".equals(orderProduct.getIncludedTax()) && ("1".equals(orderProduct.getInvoiceType()) || "2".equals(orderProduct.getInvoiceType())))) {
+                product.setIncludedTaxFlag("2");
+            } else if (orderProduct.getIncludedTax() != null && "0".equals(orderProduct.getIncludedTax()) && "3".equals(orderProduct.getInvoiceType())) {
+                product.setIncludedTaxFlag("1");
+            } else {
+                product.setIncludedTaxFlag("3");
+            }
+            //不含税可开票商品,单价/折后单价在原基础上加上税费
+            if ("0".equals(orderProduct.getIncludedTax()) && ("1".equals(orderProduct.getInvoiceType()) || "2".equals(orderProduct.getInvoiceType()))) {
+                product.setPrice(MathUtil.add(product.getPrice(), orderProduct.getAddedValueTax()));
+            }
+            orderProductList.add(product);
+        }
+        HashMap<String, Object> orderDetail = new HashMap<>();
+        orderDetail.put("addressInfo", addressInfo);
+        orderDetail.put("orderInfo", cmOrderVo);
+        orderDetail.put("productInfo", orderProductList);
+        orderDetail.put("invoiceInfo", invoiceInfo);
+        return ResponseJson.success(orderDetail);
+    }
+
+    @Override
+    public ResponseJson orderCancel(String cmAccount, String data) {
+        // 获取组织信息
+        CmApiOrganizePo organizePo = organizeMapper.getOrganizeByCmAccount(cmAccount);
+        if (null == organizePo) {
+            return ResponseJson.error("参数异常,用户不存在", null);
+        }
+        // 获取用户id
+        Integer userId = organizePo.getUserId();
+        JSONObject orderInfo = null;
+        try {
+            // 使用组织对应的公钥解密,获得订单数据
+            orderInfo = KeyUtils.decryptDataPublic(data, organizePo.getPublicKey());
+            // 私钥验签
+            String preSign = orderInfo.getString("sign");
+            orderInfo.remove("sign");
+            String sufSign = KeyUtils.buildSign(orderInfo, organizePo.getPrivateKey());
+            if (!preSign.equals(sufSign)) {
+                return ResponseJson.error("验签失败", null);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return ResponseJson.error("解密失败", null);
+        }
+        String apiOrganizeOrderId = (String) orderInfo.get("orderId");
+        if (StringUtils.isEmpty(apiOrganizeOrderId)) {
+            return ResponseJson.error("参数异常,订单Id不能为空",null);
+        }
+        CmOrderPo order = orderMapper.getOrder(userId, apiOrganizeOrderId);
+        if (null == order) {
+            return ResponseJson.error("该订单不存在");
+        }
+        if (!("11".equals(order.getStatus()) || "0".equals(order.getStatus()))) {
+            return ResponseJson.error("只有未收款未发货的订单才能取消");
+        }
+        order.setStatus("6");
+        order.setCloseReason("协销或用户主动取消订单");
+        order.setCloseTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+        orderMapper.updateOrder(order);
+        return ResponseJson.success("取消订单成功");
+    }
+
+    @Override
+    public ResponseJson payCallBack(String cmAccount, String data) {
+        // 获取组织信息
+        CmApiOrganizePo organizePo = organizeMapper.getOrganizeByCmAccount(cmAccount);
+        if (null == organizePo) {
+            return ResponseJson.error("参数异常,用户不存在", null);
+        }
+        // 获取用户id
+        Integer userId = organizePo.getUserId();
+        JSONObject orderInfo = null;
+        try {
+            // 使用组织对应的公钥解密,获得订单数据
+            orderInfo = KeyUtils.decryptDataPublic(data, organizePo.getPublicKey());
+            // 私钥验签
+            String preSign = orderInfo.getString("sign");
+            orderInfo.remove("sign");
+            String sufSign = KeyUtils.buildSign(orderInfo, organizePo.getPrivateKey());
+            if (!preSign.equals(sufSign)) {
+                return ResponseJson.error("验签失败", null);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return ResponseJson.error("解密失败", null);
+        }
+        String orderId = (String) orderInfo.get("orderId");
+        String result = (String) orderInfo.get("result");
+        Double amount = orderInfo.getDouble("amount");
+        log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>订单支付完成通知回调:orderId:" + orderId + ",amount:" + amount + ",result:" + result);
+        return ResponseJson.success("SUCCESS");
+    }
+
+    /**
+     * 设置订单发票
+     *
+     * @param orderInvoice
+     * @param invoice
+     * @param invoiceType
+     * @return
+     */
+    private boolean setInvoiceParam(Map<String, Object> orderInvoice, BpOrderInvoicePo invoice, Integer invoiceType) {
+        String invoiceTitle = (String) (null != orderInvoice.get("invoiceTitle") ? orderInvoice.get("invoiceTitle") : "");
+        invoice.setInvoiceTitle(invoiceTitle);
+        if (1 == invoiceType) {
+            // 普通发票:发票类型、发票内容(商品明细)、抬头(公司名称)、纳税人识别号[普通发票的公司]
+            String invoiceContent = (String) (null != orderInvoice.get("invoiceContent") ? orderInvoice.get("invoiceContent") : "");
+            String invoiceTitleType = (null != orderInvoice.get("invoiceTitleType") ? orderInvoice.get("invoiceTitleType") : "").toString();
+            if ("".equals(invoiceTitle) || "".equals(invoiceContent) || "".equals(invoiceTitleType)) {
+                return true;
+            }
+            if ("1".equals(invoiceTitleType)) {
+                // 企业
+                String corporationTaxNum = (String) (null != orderInvoice.get("corporationTaxNum") ? orderInvoice.get("corporationTaxNum") : "");
+                if ("".equals(corporationTaxNum)) {
+                    return true;
+                }
+                invoice.setCorporationTaxNum(corporationTaxNum);
+            }
+
+            invoice.setInvoiceContent(invoiceContent);
+        } else if (2 == invoiceType) {
+            // 增值税发票:发票类型、发票、抬头(公司名称)、纳税人识别号、注册地址、注册电话、开户银行、开户银行账户
+            String corporationTaxNum = (String) (null != orderInvoice.get("corporationTaxNum") ? orderInvoice.get("corporationTaxNum") : "");
+            String registeredAddress = (String) (null != orderInvoice.get("registeredAddress") ? orderInvoice.get("registeredAddress") : "");
+            String registeredPhone = (String) (null != orderInvoice.get("registeredPhone") ? orderInvoice.get("registeredPhone") : "");
+            String openBank = (String) (null != orderInvoice.get("openBank") ? orderInvoice.get("openBank") : "");
+            String bankAccountNo = (String) (null != orderInvoice.get("bankAccountNo") ? orderInvoice.get("bankAccountNo") : "");
+            boolean flag = "".equals(invoiceTitle) || "".equals(corporationTaxNum) || "".equals(registeredAddress) || "".equals(registeredPhone) || "".equals(openBank) || "".equals(bankAccountNo);
+            if (flag) {
+                return true;
+            }
+            invoice.setCorporationTaxNum(corporationTaxNum);
+            invoice.setRegisteredAddress(registeredAddress);
+            invoice.setRegisteredPhone(registeredPhone);
+            invoice.setOpenBank(openBank);
+            invoice.setBankAccountNo(bankAccountNo);
+        }
+        return false;
+    }
+
+    /**
+     * 整理订单商品数据
+     *
+     * @param productNum
+     * @param product
+     * @param productPrice
+     * @param priceType    0正常商品 1促销商品 2阶梯价 3复购价
+     * @param productType
+     * @return
+     */
+    private CmOrderProductPo setOrderProduct(Integer productNum, CmApiOrganizeProductPo product, BigDecimal productPrice, Integer priceType, Integer productType, BigDecimal addedValueTax) {
+        CmOrderProductPo orderProduct = new CmOrderProductPo();
+        orderProduct.setShopID(product.getShopId().longValue());
+        orderProduct.setProductID(product.getProductId());
+//        orderProduct.setOrganizeProductID(product.getId());
+        // 预留在保存保存子订单的时候添加
+        orderProduct.setProductNo(null);
+        orderProduct.setNum(productNum);
+        orderProduct.setPresentNum(0);
+        orderProduct.setProductUnit(product.getUnit());
+        if (MathUtil.compare(product.getNormalPrice(), 0) > 0) {
+            orderProduct.setNormalPrice(product.getNormalPrice());
+        } else {
+            orderProduct.setNormalPrice(BigDecimal.ZERO);
+        }
+        orderProduct.setCostPrice(product.getCostPrice());
+        orderProduct.setPrice0(product.getPrice());
+        orderProduct.setPrice1(product.getPrice());
+        orderProduct.setTotalAmount(MathUtil.mul(product.getPrice(), productNum));
+
+        orderProduct.setDiscount(new BigDecimal(100));
+        // 经理折扣(优惠金额)
+        orderProduct.setDiscountFee(new BigDecimal(0));
+        //机构税率
+        orderProduct.setTaxRate(product.getClubTaxPoint() == null ? new BigDecimal(0) : product.getClubTaxPoint());
+        //供应商税率
+        orderProduct.setSupplierTaxRate(BigDecimal.valueOf(0));
+        orderProduct.setIncludedTax(product.getIncludedTax().toString());
+        orderProduct.setInvoiceType(product.getInvoiceType().toString());
+        BigDecimal singleShouldPayTotalTax = new BigDecimal(0);
+        if (productType == 2) {
+            //促销赠品置机构税率和供应商税率为0
+            orderProduct.setTaxRate(BigDecimal.ZERO);
+            orderProduct.setSupplierTaxRate(BigDecimal.ZERO);
+        } else {
+            //不含税可开发票商品设置税费
+            if (0 == product.getIncludedTax() && (1 == product.getInvoiceType() || 2 == product.getInvoiceType())) {
+                //供应商税费(单)=成本价 * 供应商税率
+                if (product.getShopTaxPoint() == null) {
+                    orderProduct.setSupplierTaxRate(product.getClubTaxPoint());
+                } else {
+                    orderProduct.setSupplierTaxRate(product.getShopTaxPoint());
+                }
+                singleShouldPayTotalTax = MathUtil.div(MathUtil.mul(product.getCostPrice(), orderProduct.getSupplierTaxRate()), BigDecimal.valueOf(100));
+            } else if (1 == product.getIncludedTax()) {
+                //含税商品设置供应商税率
+                if (product.getShopTaxPoint() == null) {
+                    orderProduct.setSupplierTaxRate(product.getClubTaxPoint());
+                } else {
+                    orderProduct.setSupplierTaxRate(product.getShopTaxPoint());
+                }
+            } else if ((0 == product.getIncludedTax() && 3 == product.getInvoiceType()) || 2 == product.getIncludedTax()) {
+                //不含税不可开票商品和未知商品,税率置为0
+                orderProduct.setTaxRate(BigDecimal.ZERO);
+                orderProduct.setSupplierTaxRate(BigDecimal.ZERO);
+            }
+        }
+
+        orderProduct.setAddedValueTax(addedValueTax);
+        //机构税费(总)=机构税费(单) * 商品数量
+        orderProduct.setTotalAddedValueTax(MathUtil.mul(addedValueTax, productNum));
+        orderProduct.setSingleShouldPayTotalTax(singleShouldPayTotalTax);
+        //供应商税费(总)=供应商税费(单) * 商品数量
+        orderProduct.setShouldPayTotalTax(MathUtil.mul(singleShouldPayTotalTax, productNum));
+        orderProduct.setTotalFee(MathUtil.mul(productPrice, productNum));
+        orderProduct.setShouldPayFee(MathUtil.mul(productPrice, productNum));
+
+        // 商品费=成本价快照*(购买数量  + 赠品数量)
+        orderProduct.setShopProductAmount(MathUtil.mul(product.getCostPrice(), BigDecimal.valueOf(productNum)));
+        //不含税可开票商品,单价/折后单价=售价-税费
+        if (priceType == 0 || priceType == 1) {
+            //正常价格和促销价格
+            orderProduct.setPrice(product.getPrice());
+            orderProduct.setDiscountPrice(product.getPrice());
+        } else if (priceType == 2) {
+            //阶梯价
+            BigDecimal price1 = productPrice;
+            //不含税可开票商品,单价/折后单价=售价-税费
+            if (0 == product.getIncludedTax() && (1 == product.getInvoiceType() || 2 == product.getInvoiceType())) {
+                price1 = MathUtil.sub(productPrice, orderProduct.getAddedValueTax());
+            }
+            orderProduct.setPrice(price1);
+            orderProduct.setDiscountPrice(price1);
+        }
+        //应付供应商(单)=成本价+供应商税费(单)
+        BigDecimal singleShopFee = MathUtil.add(product.getCostPrice(), singleShouldPayTotalTax);
+        orderProduct.setSingleShopFee(singleShopFee);
+        // 应付供应商(总)=应付供应商(单) * 商品数量
+        orderProduct.setShopFee(MathUtil.mul(singleShopFee, BigDecimal.valueOf(productNum)));
+        orderProduct.setOtherFee(new BigDecimal(0));
+        orderProduct.setSingleOtherFee(new BigDecimal(0));
+
+        //应付采美(单)=单价+机构税费(单)-(成本(单)+供应商税费(单))
+        BigDecimal singleCmFee = MathUtil.sub(MathUtil.add(product.getPrice(), orderProduct.getAddedValueTax()), MathUtil.add(product.getCostPrice(), singleShouldPayTotalTax));
+        orderProduct.setSingleCmFee(singleCmFee);
+        // 应付采美(总)=应付采美(单)*商品数量
+        BigDecimal cmFee = MathUtil.mul(singleCmFee, BigDecimal.valueOf(productNum));
+        orderProduct.setCmFee(cmFee);
+
+        orderProduct.setTotalBeans(new BigDecimal(0));
+        orderProduct.setUseBalanceAmount(0d);
+        // 优惠金额
+        orderProduct.setPreferential(new BigDecimal(0));
+        orderProduct.setUseBalanceAmount(0d);
+        // 订单商品供应商确认标志 0否 1是
+        orderProduct.setConfirmProductFlag("0");
+
+        orderProduct.setShopName(product.getShopName());
+        orderProduct.setName(product.getName());
+        orderProduct.setPayStatus("0");
+        orderProduct.setBuyAgainFlag("0");
+        // 未出库数量
+        orderProduct.setNotOutStore(productNum);
+        // 是否已评论 1 是 0 未评论
+        orderProduct.setCommentFlag("0");
+        orderProduct.setActPreferential(new BigDecimal(0));
+        orderProduct.setActType(null);
+
+        orderProduct.setIsActProduct(product.getActStatus().toString());
+        orderProduct.setLadderPriceFlag(product.getActStatus() == 2 ? "1" : "0");
+        orderProduct.setProductImage(ProductUtils.getImageURL("product", product.getMainImage(), 0, domain));
+        orderProduct.setProductType(productType.toString());
+        //促销赠品
+        if (productType == 2) {
+            orderProduct.setPrice0(BigDecimal.ZERO);
+            orderProduct.setPrice1(BigDecimal.ZERO);
+            orderProduct.setTotalAmount(BigDecimal.ZERO);
+            orderProduct.setTotalFee(BigDecimal.ZERO);
+            orderProduct.setDiscountPrice(BigDecimal.ZERO);
+            orderProduct.setTotalAddedValueTax(BigDecimal.ZERO);
+            orderProduct.setShouldPayTotalTax(BigDecimal.ZERO);
+        }
+        return orderProduct;
+    }
+
+
+
+
+    /**
+     * 计算总运费
+     *
+     * @param provinceId
+     * @param cityId
+     * @return totalPostageFee
+     */
+    public Double computedPostageFee(Integer provinceId, Integer cityId) {
+        if (202 == cityId) {
+            // 深圳市内运费10元
+            return 10d;
+        } else if (19 == provinceId) {
+            // 广东省内深圳市外运费15元
+            return 15d;
+        } else {
+            return -1d;
+        }
+    }
+
+    /**
+     * 保存子订单,并返回子订单ids
+     *
+     * @param order
+     * @param orderProductList
+     * @param shopId
+     * @param shopNote
+     * @return
+     */
+    private CmShopOrderPo saveShopOrder(CmOrderPo order, List<CmOrderProductPo> orderProductList, Integer shopId, String shopNote) {
+        /*
+         *  初始化子订单信息
+         */
+        CmShopOrderPo shopOrder = new CmShopOrderPo();
+        // 子订单编号
+        String shopOrderNo = "";
+        String maxShopOrderNo = orderMapper.findMaxShopOrderNo(order.getOrderID());
+        if (StringUtils.isNotBlank(maxShopOrderNo)) {
+            shopOrderNo = maxShopOrderNo;
+            shopOrder.setShopOrderNo(OrderNoUtils.getShopOrderNo(order.getOrderNo(), Integer.parseInt(shopOrderNo.substring(shopOrderNo.length() - 2, shopOrderNo.length())) + 1));
+        } else {
+            shopOrder.setShopOrderNo(OrderNoUtils.getShopOrderNo(order.getOrderNo(), 1));
+        }
+        shopOrder.setShopID(shopId);
+        shopOrder.setClubID(order.getClubID().intValue());
+        shopOrder.setOrderID(order.getOrderID());
+        shopOrder.setOrderNo(order.getOrderNo());
+        shopOrder.setUserID(order.getUserID().intValue());
+        shopOrder.setOrganizeID(order.getOrganizeID());
+        /*
+         *  统计子订单金额信息
+         */
+        // 订单总金额
+        BigDecimal totalAmount = new BigDecimal(0);
+        // 商品总金额
+        BigDecimal productAmount = new BigDecimal(0);
+        // 需要支付金额
+        BigDecimal needPayAmount = new BigDecimal(0);
+        // 优惠金额
+        BigDecimal preferential = new BigDecimal(0);
+        // 佣金
+        BigDecimal brokerage = new BigDecimal(0);
+        // 商品费
+        BigDecimal shopProductAmount = new BigDecimal(0);
+        // 供应商税费
+        BigDecimal shopTaxFee = new BigDecimal(0);
+        // 总购买数
+        Integer buyNum = 0;
+        // 计算子订单信息
+        for (CmOrderProductPo orderProduct : orderProductList) {
+            if (shopId.longValue() == orderProduct.getShopID()) {
+                // 商品总金额
+                productAmount = MathUtil.add(productAmount, orderProduct.getTotalAmount());
+                // 订单总金额 包括税费
+                totalAmount = MathUtil.add(totalAmount, orderProduct.getTotalFee());
+                // 应付金额
+                needPayAmount = MathUtil.add(needPayAmount, orderProduct.getShouldPayFee());
+                // 总购买数
+                buyNum += orderProduct.getNum();
+                preferential = MathUtil.add(preferential, orderProduct.getPreferential());
+                brokerage = MathUtil.add(brokerage, orderProduct.getCmFee());
+                if (null != orderProduct.getShopProductAmount()) {
+                    shopProductAmount = MathUtil.add(shopProductAmount, orderProduct.getShopProductAmount());
+                }
+                if (null != orderProduct.getShouldPayTotalTax()) {
+                    shopTaxFee = MathUtil.add(shopTaxFee, orderProduct.getShouldPayTotalTax());
+                }
+            }
+        }
+        shopOrder.setPromotionFullReduction(BigDecimal.ZERO);
+        // freePostFlag: 0包邮 -1到付 1 有运费
+        // fee: 运费:-1到付,0包邮,其他为具体运费(v5.0版本已废弃,运费已使用商品形式存储)
+        if ("1".equals(order.getFreePostFlag())) {
+            shopOrder.setFee(0d);
+        } else {
+            shopOrder.setFee(Double.parseDouble(order.getFreePostFlag()));
+        }
+        shopOrder.setNote(shopNote);
+        shopOrder.setOrderTime(order.getOrderTime());
+        shopOrder.setDiscountFee(BigDecimal.ZERO);
+        shopOrder.setCanRefundFlag(1);
+        shopOrder.setCanRefundAmount(needPayAmount.doubleValue());
+        shopOrder.setAccountAmount(BigDecimal.ZERO);
+        // 佣金 采美应收
+        shopOrder.setBrokerage(brokerage);
+        shopOrder.setBuyStatus("1");
+        shopOrder.setPresentNum(0);
+        shopOrder.setUseBeanFlag(0);
+        shopOrder.setUseBeanAmount(0);
+        shopOrder.setUseBalanceFlag(0);
+        shopOrder.setRefundStatus(0);
+        shopOrder.setRefundsAmount(BigDecimal.ZERO);
+        shopOrder.setPayStatus("1");
+        shopOrder.setZeroCostFlag(0);
+        shopOrder.setSendOutStatus("1");
+        shopOrder.setPayFlag("0");
+        // 订单状态标识,1:非退货退款订单、2:退货退款中、3退货退款完成
+        shopOrder.setOrderStatusFlag("1");
+        shopOrder.setDelFlag("0");
+        shopOrder.setOrderBeanAmount(0);
+        // 购买商品数
+        shopOrder.setItemCount(buyNum);
+        // 普通订单 1 协销订单0 与cm_order一样
+        shopOrder.setOrderType(0);
+        shopOrder.setStatus(1);
+        shopOrder.setOrderSubmitType(order.getOrderSubmitType());
+        shopOrder.setTotalAmount(totalAmount);
+        shopOrder.setProductAmount(productAmount);
+        shopOrder.setNeedPayAmount(needPayAmount);
+        shopOrder.setPreferential(preferential);
+        shopOrder.setShopProductAmount(shopProductAmount);
+        // 付给供应商运费
+        shopOrder.setShopPostFee(BigDecimal.ZERO);
+        // 付给供应商税费
+        shopOrder.setShopTaxFee(shopTaxFee);
+        // 已付款金额
+        shopOrder.setPayedShopAmount(BigDecimal.ZERO);
+        // 付第三方
+        shopOrder.setShopOtherFee(BigDecimal.ZERO);
+        // 付供应商 = 商品费 + 运费 + 税费
+        shopOrder.setShouldPayShopAmount(MathUtil.add(shopProductAmount, shopTaxFee));
+        // 订单能否拆分 1 为可拆分, 0为不可拆分
+        if (buyNum > 1) {
+            shopOrder.setSplitFlag("1");
+        } else {
+            shopOrder.setSplitFlag("0");
+        }
+        /*
+         * 保存子订单信息到数据库
+         */
+        orderMapper.insertShopOrder(shopOrder);
+        log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>新增子订单(insert[cm_shop_order])shopOrderId:" + shopOrder.getShopOrderID());
+        return shopOrder;
+    }
+
+    /**
+     * 保存运费子订单,并返回子订单ids
+     *
+     * @param order
+     * @param num
+     * @return
+     */
+    private String setPostFeeShopOrder(CmOrderPo order, String shopOrderIds, int num) {
+        ProductPo product = productMapper.findPostFeeProduct();
+        CmShopOrderPo newShopOrder = new CmShopOrderPo();
+        String shopOrderNo = OrderNoUtils.getShopOrderNo(order.getOrderNo(), num + 1);
+        newShopOrder.setShopOrderNo(shopOrderNo);
+        newShopOrder.setOrderNo(order.getOrderNo());
+        newShopOrder.setOrderID(order.getOrderID());
+        newShopOrder.setUserID(order.getUserID().intValue());
+        newShopOrder.setOrderType(order.getOrderType());
+        newShopOrder.setOrderSubmitType(order.getOrderSubmitType());
+        newShopOrder.setPresentNum(0);
+        newShopOrder.setItemCount(1);
+        //运费商品供应商ID默认998
+        newShopOrder.setShopID(product.getShopID());
+        newShopOrder.setFee(order.getFreight().doubleValue());
+        newShopOrder.setProductAmount(order.getFreight());
+        newShopOrder.setTotalAmount(order.getFreight());
+        newShopOrder.setNeedPayAmount(order.getFreight());
+        newShopOrder.setDiscountAmount(BigDecimal.ZERO);
+        newShopOrder.setPayFlag("0");
+        newShopOrder.setOrderTime(order.getOrderTime());
+        newShopOrder.setPayStatus("3");
+        newShopOrder.setSendOutStatus("3");
+        newShopOrder.setTotalAddedValueTax(BigDecimal.ZERO);
+        newShopOrder.setCanRefundAmount(0D);
+        newShopOrder.setRefundAmount(0D);
+        newShopOrder.setRefundStatus(0);
+        newShopOrder.setClubID(order.getClubID().intValue());
+        if (null != order.getSpID()) {
+            newShopOrder.setSpID(order.getSpID().intValue());
+        }
+        if (null != order.getMainSpID()) {
+            newShopOrder.setMainSpID(order.getMainSpID().intValue());
+        }
+        newShopOrder.setAutoOverTimeMills(0L);
+        newShopOrder.setAutoReceiveTimeMills(0L);
+        newShopOrder.setOrderBeanAmount(0);
+        newShopOrder.setUseBeanFlag(0);
+        newShopOrder.setUseBeanAmount(0);
+        newShopOrder.setAccountAmount(BigDecimal.ZERO);
+        newShopOrder.setCanRefundFlag(1);
+        newShopOrder.setBuyStatus("1");
+        newShopOrder.setOutStoreNum(0);
+        newShopOrder.setDelFlag("0");
+        newShopOrder.setPayFlag("0");
+        // 订单默认可拆分
+        newShopOrder.setSplitFlag("1");
+        /*
+         * 保存子订单信息到数据库
+         */
+        orderMapper.insertShopOrder(newShopOrder);
+        log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>新增子订单(运费商品)(insert[cm_shop_order])shopOrderId:" + newShopOrder.getShopOrderID());
+
+        /*
+         * 插入订单 运费商品
+         */
+        CmOrderProductPo feeOrderProduct = new CmOrderProductPo();
+        feeOrderProduct.setProductType("0");
+        feeOrderProduct.setOrderNo(order.getOrderNo());
+        feeOrderProduct.setOrderID(order.getOrderID());
+        feeOrderProduct.setShopOrderID(newShopOrder.getShopOrderID());
+        feeOrderProduct.setShopOrderNo(newShopOrder.getShopOrderNo());
+        feeOrderProduct.setShopID(product.getShopID().longValue());
+        feeOrderProduct.setProductID(999);
+        feeOrderProduct.setNum(1);
+        feeOrderProduct.setPresentNum(0);
+        feeOrderProduct.setOutStoreType("0");
+        feeOrderProduct.setProps(product.getProps());
+        feeOrderProduct.setProductNo(product.getProductCode());
+        feeOrderProduct.setPrice(order.getFreight());
+        feeOrderProduct.setNormalPrice(order.getFreight());
+        feeOrderProduct.setPrice0(order.getFreight());
+        feeOrderProduct.setPrice1(order.getFreight());
+        feeOrderProduct.setTotalAmount(order.getFreight());
+        feeOrderProduct.setTotalFee(order.getFreight());
+        feeOrderProduct.setShouldPayFee(order.getFreight());
+        feeOrderProduct.setDiscount(new BigDecimal(100));
+        feeOrderProduct.setDiscountPrice(order.getFreight());
+        feeOrderProduct.setTaxRate(new BigDecimal(100));
+        feeOrderProduct.setAddedValueTax(order.getFreight());
+        feeOrderProduct.setTotalAddedValueTax(BigDecimal.ZERO);
+        feeOrderProduct.setShopFee(BigDecimal.ZERO);
+        feeOrderProduct.setOtherFee(BigDecimal.ZERO);
+        feeOrderProduct.setCmFee(order.getFreight());
+        feeOrderProduct.setSingleShopFee(BigDecimal.ZERO);
+        feeOrderProduct.setSingleOtherFee(BigDecimal.ZERO);
+        feeOrderProduct.setSingleCmFee(order.getFreight());
+        feeOrderProduct.setTotalBeans(BigDecimal.ZERO);
+        feeOrderProduct.setUseBalanceAmount(0D);
+        feeOrderProduct.setUseBeanAmount(0);
+        feeOrderProduct.setNotOutStore(0);
+        feeOrderProduct.setCmbeanPrice(0);
+        feeOrderProduct.setBuyAgainFlag("0");
+        feeOrderProduct.setShopName(product.getShopName());
+        feeOrderProduct.setName(product.getName());
+        feeOrderProduct.setIncludedTax(product.getIncludedTax());
+        feeOrderProduct.setInvoiceType(product.getInvoiceType());
+        // 保存订单商品数据
+        orderMapper.insertOrderProduct(feeOrderProduct);
+        log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>保存订单运费商品(insert[cm_order_product])orderId:" + feeOrderProduct.getOrderProductID());
+
+        shopOrderIds += (("".equals(shopOrderIds) ? "" : ",") + newShopOrder.getShopOrderID());
+        return shopOrderIds;
+    }
+
+
+    private List<DiscernReceiptVo> getDiscernReceipt(OrderVo order) {
+        //支付记录
+        List<DiscernReceiptVo> discernReceiptList = orderMapper.findDiscernReceipt(order.getOrderID().intValue());
+        BigDecimal receiptAmount = BigDecimal.ZERO;
+        //订单款
+        if (discernReceiptList != null && discernReceiptList.size() > 0) {
+            for (DiscernReceiptVo discernReceipt : discernReceiptList) {
+                receiptAmount = receiptAmount.add(discernReceipt.getAssociateAmount());
+                if (discernReceipt.getPayType() != null) {
+                    discernReceipt.setPayType(ReceivablesType.getReceivablesType(Integer.parseInt(discernReceipt.getPayType())));
+                }
+            }
+        }
+        order.setPendingPayments(MathUtil.sub(order.getPayableAmount(), receiptAmount));
+        //支付总金额
+        order.setReceiptAmount(receiptAmount);
+        return discernReceiptList;
+    }
+
+}

+ 197 - 0
src/main/java/com/caimei/service/impl/ProductServiceImpl.java

@@ -0,0 +1,197 @@
+package com.caimei.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.caimei.mapper.OrganizeMapper;
+import com.caimei.mapper.ProductMapper;
+import com.caimei.model.ResponseJson;
+import com.caimei.model.po.*;
+import com.caimei.model.vo.LadderPriceVo;
+import com.caimei.model.vo.ProductDetailVo;
+import com.caimei.model.vo.ProductListVo;
+import com.caimei.model.vo.ProductVo;
+import com.caimei.service.ProductService;
+import com.caimei.utils.MathUtil;
+import com.caimei.utils.ProductUtils;
+import com.caimei.utils.KeyUtils;
+import com.github.pagehelper.PageHelper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.*;
+
+/**
+ * @author Aslee
+ */
+@Slf4j
+@Service
+public class ProductServiceImpl implements ProductService {
+    @Resource
+    OrganizeMapper organizeMapper;
+    @Resource
+    private ProductMapper productMapper;
+
+    @Value("${caimei.oldapi}")
+    private String domain;
+
+    @Override
+    public ResponseJson<List<ProductListVo>> productList(String cmAccount, String data){
+        // 获取组织信息
+        CmApiOrganizePo organizePo = organizeMapper.getOrganizeByCmAccount(cmAccount);
+        if (null == organizePo) {
+            return ResponseJson.error("参数异常,用户不存在", null);
+        }
+        JSONObject productInfo = null;
+        try {
+            // 使用组织对应的公钥解密,获得商品数据
+            productInfo = KeyUtils.decryptDataPublic(data, organizePo.getPublicKey());
+            // 私钥验签
+            String preSign = productInfo.getString("sign");
+            productInfo.remove("sign");
+            String sufSign = KeyUtils.buildSign(productInfo, organizePo.getPrivateKey());
+            if (!preSign.equals(sufSign)) {
+                return ResponseJson.error("验签失败", null);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return ResponseJson.error("解密失败", null);
+        }
+        Integer pageNum = (Integer) (null == productInfo.get("pageNum") ? 1 : productInfo.get("pageNum"));
+        Integer pageSize = (Integer) (null == productInfo.get("pageSize") ? 10 : productInfo.get("pageSize"));
+        String productName = (String) productInfo.get("productName");
+        PageHelper.startPage(pageNum, pageSize);
+        List<ProductVo> productList = productMapper.getProductList(organizePo.getOrganizeId(), productName);
+        List<ProductListVo> resultVoList = new ArrayList<>();
+        DecimalFormat decimalFormat = new DecimalFormat("0000");
+        for (ProductVo product : productList) {
+            setProductPrice(product);
+            ProductListVo productResult = new ProductListVo();
+            productResult.setProductId(decimalFormat.format(product.getProductId()));
+            productResult.setProductName(product.getProductName());
+            productResult.setShopName(product.getShopName());
+            productResult.setImage(product.getMainImage());
+            productResult.setPrice(product.getRetailPrice());
+            productResult.setBrandName(product.getBrandName());
+            productResult.setMinBuyNumber(product.getMinBuyNumber());
+            productResult.setUnit(product.getUnit());
+            productResult.setLadderPriceFlag(product.getLadderPriceFlag());
+            productResult.setLadderPriceList(product.getLadderPriceList());
+            resultVoList.add(productResult);
+        }
+        return ResponseJson.success(resultVoList);
+    }
+
+
+    @Override
+    public ResponseJson<ProductDetailVo> productDetail(String cmAccount, String data) {
+        // 获取组织信息
+        CmApiOrganizePo organizePo = organizeMapper.getOrganizeByCmAccount(cmAccount);
+        if (null == organizePo) {
+            return ResponseJson.error("参数异常,用户不存在", null);
+        }
+        JSONObject productInfo = null;
+        try {
+            // 使用组织对应的公钥解密,获得订单数据
+            productInfo = KeyUtils.decryptDataPublic(data, organizePo.getPublicKey());
+            // 私钥验签
+            String preSign = productInfo.getString("sign");
+            productInfo.remove("sign");
+            String sufSign = KeyUtils.buildSign(productInfo, organizePo.getPrivateKey());
+            if (!preSign.equals(sufSign)) {
+                return ResponseJson.error("验签失败", null);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return ResponseJson.error("解密失败", null);
+        }
+        String productId = (String) productInfo.get("productId");
+        ProductVo product = productMapper.findProductByProductId(organizePo.getOrganizeId(), productId);
+        if (null == product) {
+            return ResponseJson.error("商品不存在", null);
+        }
+        setProductPrice(product);
+        ProductDetailVo productDetail = new ProductDetailVo();
+        productDetail.setImage(ProductUtils.getImageURL("product", product.getMainImage(), 0, domain));
+        //商品图片
+        List<ProductImagePo> imageList = productMapper.findProductImagesByOriginalId(product.getOriginalProductId());
+        for (ProductImagePo image : imageList) {
+            String imageURL = ProductUtils.getImageURL("product", image.getImage(), 0, domain);
+            image.setImage(imageURL);
+        }
+        productDetail.setImageList(imageList);
+        DecimalFormat decimalFormat = new DecimalFormat("0000");
+        //商品详情
+        ProductDetailInfoPo info = productMapper.findProductDetailByOriginalId(product.getOriginalProductId());
+        productDetail.setProductDetail(info);
+        productDetail.setProductId(decimalFormat.format(product.getProductId()));
+        productDetail.setProductName(product.getProductName());
+        productDetail.setShopName(product.getShopName());
+        productDetail.setImage(product.getMainImage());
+        productDetail.setPrice(product.getRetailPrice());
+        productDetail.setBrandName(product.getBrandName());
+        productDetail.setMinBuyNumber(product.getMinBuyNumber());
+        productDetail.setUnit(product.getUnit());
+        productDetail.setLadderPriceFlag(product.getLadderPriceFlag());
+        productDetail.setLadderPriceList(product.getLadderPriceList());
+        return ResponseJson.success(productDetail);
+    }
+
+
+    public void setProductPrice(ProductVo product) {
+        // 设置图片
+        product.setMainImage(ProductUtils.getImageURL("product", product.getMainImage(), 0, domain));
+        // 设置商品展示价格
+        if (1 == product.getLadderPriceFlag()) {
+            // 启用阶梯价格
+            getLadderPrice(product);
+        } else {
+            product.setLadderPriceFlag(0);
+            product.setRetailPrice(product.getPrice());
+        }
+        //添加税费
+        boolean addTaxFlag = (0 == product.getIncludedTax() && (1 == product.getInvoiceType() || 2 == product.getInvoiceType()));
+        if (addTaxFlag) {
+            BigDecimal addedValueTax = MathUtil.div(MathUtil.mul(product.getRetailPrice(), product.getClubTaxPoint()), BigDecimal.valueOf(100));
+            BigDecimal price = MathUtil.add(product.getRetailPrice(), addedValueTax);
+            product.setRetailPrice(price);
+        }
+    }
+
+
+    public void getLadderPrice(ProductVo product) {
+        // 启用阶梯价格
+        List<LadderPriceVo> ladderPriceList = productMapper.findLadderPriceByProductId(product.getProductId());
+        if (ladderPriceList.size() > 0) {
+            for (int i = 0; i < ladderPriceList.size(); i++) {
+                if (null != ladderPriceList.get(i)) {
+                    String buyNumRangeShow;
+                    if ((i + 1) < ladderPriceList.size() && null != ladderPriceList.get(i + 1)) {
+                        buyNumRangeShow = ladderPriceList.get(i).getBuyNum() + "~" + (ladderPriceList.get(i + 1).getBuyNum() - 1L);
+                    } else {
+                        buyNumRangeShow = "≥" + ladderPriceList.get(i).getBuyNum();
+                    }
+                    ladderPriceList.get(i).setBuyNumRangeShow(buyNumRangeShow);
+                }
+            }
+            product.setRetailPrice(ladderPriceList.get(0).getBuyPrice());
+            product.setMinBuyNumber(ladderPriceList.get(0).getBuyNum());
+            product.setLadderPriceList(ladderPriceList);
+            //阶梯价列表添加税费
+            boolean addTaxFlag = (0 == product.getIncludedTax() && (1 == product.getInvoiceType() || 2 == product.getInvoiceType()));
+            if (addTaxFlag) {
+                ladderPriceList.forEach(item -> {
+                    item.setBuyPrice(MathUtil.add(item.getBuyPrice(), MathUtil.div(MathUtil.mul(item.getBuyPrice(), product.getClubTaxPoint()), 100)));
+                });
+            }
+        } else {
+            // 阶梯价格异常,关闭阶梯价格
+            product.setLadderPriceFlag(0);
+            product.setRetailPrice(product.getPrice());
+        }
+    }
+
+
+}

+ 128 - 0
src/main/java/com/caimei/utils/AES.java

@@ -0,0 +1,128 @@
+package com.caimei.utils;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.UnsupportedEncodingException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+
+public class AES {
+    /**
+     * 加密
+     *
+     * @param content  需要加密的内容
+     * @param password 加密密码
+     * @return
+     */
+    public static byte[] encrypt(byte[] data, byte[] key) {
+        CheckUtils.notEmpty(data, "data");
+        CheckUtils.notEmpty(key, "key");
+        if (key.length < 16) {
+            throw new RuntimeException("Invalid AES key length (must be 16 bytes)");
+        }
+        try {
+            SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
+            byte[] enCodeFormat = secretKey.getEncoded();
+            SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "AES");
+            Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.AES_ALGORITHM);// 创建密码器
+            cipher.init(Cipher.ENCRYPT_MODE, seckey);// 初始化
+            byte[] result = cipher.doFinal(data);
+            return result; // 加密
+        } catch (Exception e) {
+            throw new RuntimeException("encrypt fail!", e);
+        }
+    }
+
+    /**
+     * 解密
+     *
+     * @param content  待解密内容
+     * @param password 解密密钥
+     * @return
+     */
+    public static byte[] decrypt(byte[] data, byte[] key) {
+        CheckUtils.notEmpty(data, "data");
+        CheckUtils.notEmpty(key, "key");
+        System.out.println(key.length);
+        if (key.length < 16) {
+            throw new RuntimeException("Invalid AES key length (must be 16 bytes)");
+        }
+        try {
+            SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
+            byte[] enCodeFormat = secretKey.getEncoded();
+            SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "AES");
+            Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.AES_ALGORITHM);// 创建密码器
+            cipher.init(Cipher.DECRYPT_MODE, seckey);// 初始化
+            byte[] result = cipher.doFinal(data);
+            return result; // 加密
+        } catch (Exception e) {
+            throw new RuntimeException("decrypt fail!", e);
+        }
+    }
+
+    public static String encryptToBase64(String data, String key) {
+        try {
+            byte[] valueByte = encrypt(data.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING), key.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING));
+            return new String(Base64.encode(valueByte));
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("encrypt fail!", e);
+        }
+
+    }
+
+    public static String decryptFromBase64(String data, String key) {
+        try {
+            byte[] originalData = Base64.decode(data.getBytes());
+            byte[] valueByte = decrypt(originalData, key.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING));
+            return new String(valueByte, ConfigureEncryptAndDecrypt.CHAR_ENCODING);
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("decrypt fail!", e);
+        }
+    }
+
+    public static String encryptWithKeyBase64(String data, String key) {
+        try {
+            byte[] valueByte = encrypt(data.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING), key.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING));
+            return new String(Base64.encode(valueByte));
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("encrypt fail!", e);
+        }
+    }
+
+    public static String decryptWithKeyBase64(String data, String key) {
+        try {
+            byte[] originalData = Base64.decode(data.getBytes());
+            byte[] valueByte = decrypt(originalData, key.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING));
+            return new String(valueByte, ConfigureEncryptAndDecrypt.CHAR_ENCODING);
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("decrypt fail!", e);
+        }
+    }
+
+    public static byte[] genarateRandomKey() {
+        KeyGenerator keygen = null;
+        try {
+            keygen = KeyGenerator.getInstance(ConfigureEncryptAndDecrypt.AES_ALGORITHM);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(" genarateRandomKey fail!", e);
+        }
+        SecureRandom random = new SecureRandom();
+        keygen.init(random);
+        Key key = keygen.generateKey();
+        return key.getEncoded();
+    }
+
+    public static String genarateRandomKeyWithBase64() {
+        return new String(Base64.encode(genarateRandomKey()));
+    }
+
+    public static void main(String[] args) {
+        String a = "123456";
+        String key = "1201jwe92123fdsd";
+        System.out.println(encryptToBase64(a, key));
+    }
+
+}

+ 1 - 1
src/main/java/caimei/utils/AliyunSmsUtil.java → src/main/java/com/caimei/utils/AliyunSmsUtil.java

@@ -1,4 +1,4 @@
-package caimei.utils;
+package com.caimei.utils;
 
 import com.aliyuncs.DefaultAcsClient;
 import com.aliyuncs.IAcsClient;

+ 601 - 0
src/main/java/com/caimei/utils/Base64.java

@@ -0,0 +1,601 @@
+package com.caimei.utils;
+
+import java.io.UnsupportedEncodingException;
+
+public class Base64 {
+    /**
+     * Chunk size per RFC 2045 section 6.8.
+     *
+     * <p>The {@value} character limit does not count the trailing CRLF, but counts
+     * all other characters, including any equal signs.</p>
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a>
+     */
+    static final int CHUNK_SIZE = 76;
+
+    /**
+     * Chunk separator per RFC 2045 section 2.1.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
+     */
+    static final byte[] CHUNK_SEPARATOR = "\r\n".getBytes();
+
+    /**
+     * The base length.
+     */
+    static final int BASELENGTH = 255;
+
+    /**
+     * Lookup length.
+     */
+    static final int LOOKUPLENGTH = 64;
+
+    /**
+     * Used to calculate the number of bits in a byte.
+     */
+    static final int EIGHTBIT = 8;
+
+    /**
+     * Used when encoding something which has fewer than 24 bits.
+     */
+    static final int SIXTEENBIT = 16;
+
+    /**
+     * Used to determine how many bits data contains.
+     */
+    static final int TWENTYFOURBITGROUP = 24;
+
+    /**
+     * Used to get the number of Quadruples.
+     */
+    static final int FOURBYTE = 4;
+
+    /**
+     * Used to test the sign of a byte.
+     */
+    static final int SIGN = -128;
+
+    /**
+     * Byte used to pad output.
+     */
+    static final byte PAD = (byte) '=';
+
+    // Create arrays to hold the base64 characters and a
+    // lookup for base64 chars
+    private static byte[] base64Alphabet = new byte[BASELENGTH];
+    private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
+
+    // Populating the lookup and character arrays
+    static {
+        for (int i = 0; i < BASELENGTH; i++) {
+            base64Alphabet[i] = (byte) -1;
+        }
+        for (int i = 'Z'; i >= 'A'; i--) {
+            base64Alphabet[i] = (byte) (i - 'A');
+        }
+        for (int i = 'z'; i >= 'a'; i--) {
+            base64Alphabet[i] = (byte) (i - 'a' + 26);
+        }
+        for (int i = '9'; i >= '0'; i--) {
+            base64Alphabet[i] = (byte) (i - '0' + 52);
+        }
+
+        base64Alphabet['+'] = 62;
+        base64Alphabet['/'] = 63;
+
+        for (int i = 0; i <= 25; i++) {
+            lookUpBase64Alphabet[i] = (byte) ('A' + i);
+        }
+
+        for (int i = 26, j = 0; i <= 51; i++, j++) {
+            lookUpBase64Alphabet[i] = (byte) ('a' + j);
+        }
+
+        for (int i = 52, j = 0; i <= 61; i++, j++) {
+            lookUpBase64Alphabet[i] = (byte) ('0' + j);
+        }
+
+        lookUpBase64Alphabet[62] = (byte) '+';
+        lookUpBase64Alphabet[63] = (byte) '/';
+    }
+
+    private static boolean isBase64(byte octect) {
+        if (octect == PAD) {
+            return true;
+        } else if (base64Alphabet[octect] == -1) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Tests a given byte array to see if it contains
+     * only valid characters within the Base64 alphabet.
+     *
+     * @param arrayOctect byte array to test
+     * @return true if all bytes are valid characters in the Base64
+     * alphabet or if the byte array is empty; false, otherwise
+     */
+    public static boolean isArrayByteBase64(byte[] arrayOctect) {
+
+        arrayOctect = discardWhitespace(arrayOctect);
+
+        int length = arrayOctect.length;
+        if (length == 0) {
+            // shouldn't a 0 length array be valid base64 data?
+            // return false;
+            return true;
+        }
+        for (int i = 0; i < length; i++) {
+            if (!isBase64(arrayOctect[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Encodes binary data using the base64 algorithm but
+     * does not chunk the output.
+     *
+     * @param binaryData binary data to encode
+     * @return Base64 characters
+     */
+    public static byte[] encodeBase64(byte[] binaryData) {
+        return encodeBase64(binaryData, false);
+    }
+
+    /**
+     * Encodes binary data using the base64 algorithm and chunks
+     * the encoded output into 76 character blocks
+     *
+     * @param binaryData binary data to encode
+     * @return Base64 characters chunked in 76 character blocks
+     */
+    public static byte[] encodeBase64Chunked(byte[] binaryData) {
+        return encodeBase64(binaryData, true);
+    }
+
+    /**
+     * Decodes a byte[] containing containing
+     * characters in the Base64 alphabet.
+     *
+     * @param pArray A byte array containing Base64 character data
+     * @return a byte array containing binary data
+     */
+    public static byte[] decode(byte[] pArray) {
+        return decodeBase64(pArray);
+    }
+
+    /**
+     * Encodes binary data using the base64 algorithm, optionally
+     * chunking the output into 76 character blocks.
+     *
+     * @param binaryData Array containing binary data to encode.
+     * @param isChunked  if isChunked is true this encoder will chunk
+     *                   the base64 output into 76 character blocks
+     * @return Base64-encoded data.
+     */
+    public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) {
+        int lengthDataBits = binaryData.length * EIGHTBIT;
+        int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
+        int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
+        byte encodedData[] = null;
+        int encodedDataLength = 0;
+        int nbrChunks = 0;
+
+        if (fewerThan24bits != 0) {
+            //data not divisible by 24 bit
+            encodedDataLength = (numberTriplets + 1) * 4;
+        } else {
+            // 16 or 8 bit
+            encodedDataLength = numberTriplets * 4;
+        }
+
+        // If the output is to be "chunked" into 76 character sections,
+        // for compliance with RFC 2045 MIME, then it is important to
+        // allow for extra length to account for the separator(s)
+        if (isChunked) {
+
+            nbrChunks =
+                    (CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math.ceil((float) encodedDataLength / CHUNK_SIZE));
+            encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;
+        }
+
+        encodedData = new byte[encodedDataLength];
+
+        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
+
+        int encodedIndex = 0;
+        int dataIndex = 0;
+        int i = 0;
+        int nextSeparatorIndex = CHUNK_SIZE;
+        int chunksSoFar = 0;
+
+        //log.debug("number of triplets = " + numberTriplets);
+        for (i = 0; i < numberTriplets; i++) {
+            dataIndex = i * 3;
+            b1 = binaryData[dataIndex];
+            b2 = binaryData[dataIndex + 1];
+            b3 = binaryData[dataIndex + 2];
+
+            //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3);
+
+            l = (byte) (b2 & 0x0f);
+            k = (byte) (b1 & 0x03);
+
+            byte val1 =
+                    ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+            byte val2 =
+                    ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
+            byte val3 =
+                    ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
+
+            encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
+            //log.debug( "val2 = " + val2 );
+            //log.debug( "k4   = " + (k<<4) );
+            //log.debug(  "vak  = " + (val2 | (k<<4)) );
+            encodedData[encodedIndex + 1] =
+                    lookUpBase64Alphabet[val2 | (k << 4)];
+            encodedData[encodedIndex + 2] =
+                    lookUpBase64Alphabet[(l << 2) | val3];
+            encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
+
+            encodedIndex += 4;
+
+            // If we are chunking, let's put a chunk separator down.
+            if (isChunked) {
+                // this assumes that CHUNK_SIZE % 4 == 0
+                if (encodedIndex == nextSeparatorIndex) {
+                    System.arraycopy(
+                            CHUNK_SEPARATOR,
+                            0,
+                            encodedData,
+                            encodedIndex,
+                            CHUNK_SEPARATOR.length);
+                    chunksSoFar++;
+                    nextSeparatorIndex =
+                            (CHUNK_SIZE * (chunksSoFar + 1)) +
+                                    (chunksSoFar * CHUNK_SEPARATOR.length);
+                    encodedIndex += CHUNK_SEPARATOR.length;
+                }
+            }
+        }
+
+        // form integral number of 6-bit groups
+        dataIndex = i * 3;
+
+        if (fewerThan24bits == EIGHTBIT) {
+            b1 = binaryData[dataIndex];
+            k = (byte) (b1 & 0x03);
+            //log.debug("b1=" + b1);
+            //log.debug("b1<<2 = " + (b1>>2) );
+            byte val1 =
+                    ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+            encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
+            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
+            encodedData[encodedIndex + 2] = PAD;
+            encodedData[encodedIndex + 3] = PAD;
+        } else if (fewerThan24bits == SIXTEENBIT) {
+
+            b1 = binaryData[dataIndex];
+            b2 = binaryData[dataIndex + 1];
+            l = (byte) (b2 & 0x0f);
+            k = (byte) (b1 & 0x03);
+
+            byte val1 =
+                    ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+            byte val2 =
+                    ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
+
+            encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
+            encodedData[encodedIndex + 1] =
+                    lookUpBase64Alphabet[val2 | (k << 4)];
+            encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
+            encodedData[encodedIndex + 3] = PAD;
+        }
+
+        if (isChunked) {
+            // we also add a separator to the end of the final chunk.
+            if (chunksSoFar < nbrChunks) {
+                System.arraycopy(
+                        CHUNK_SEPARATOR,
+                        0,
+                        encodedData,
+                        encodedDataLength - CHUNK_SEPARATOR.length,
+                        CHUNK_SEPARATOR.length);
+            }
+        }
+
+        return encodedData;
+    }
+
+    /**
+     * Decodes Base64 data into octects
+     *
+     * @param base64Data Byte array containing Base64 data
+     * @return Array containing decoded data.
+     */
+    public static byte[] decodeBase64(byte[] base64Data) {
+        // RFC 2045 requires that we discard ALL non-Base64 characters
+        base64Data = discardNonBase64(base64Data);
+
+        // handle the edge case, so we don't have to worry about it later
+        if (base64Data.length == 0) {
+            return new byte[0];
+        }
+
+        int numberQuadruple = base64Data.length / FOURBYTE;
+        byte decodedData[] = null;
+        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
+
+        // Throw away anything not in base64Data
+
+        int encodedIndex = 0;
+        int dataIndex = 0;
+        {
+            // this sizes the output array properly - rlw
+            int lastData = base64Data.length;
+            // ignore the '=' padding
+            while (base64Data[lastData - 1] == PAD) {
+                if (--lastData == 0) {
+                    return new byte[0];
+                }
+            }
+            decodedData = new byte[lastData - numberQuadruple];
+        }
+
+        for (int i = 0; i < numberQuadruple; i++) {
+            dataIndex = i * 4;
+            marker0 = base64Data[dataIndex + 2];
+            marker1 = base64Data[dataIndex + 3];
+
+            b1 = base64Alphabet[base64Data[dataIndex]];
+            b2 = base64Alphabet[base64Data[dataIndex + 1]];
+
+            if (marker0 != PAD && marker1 != PAD) {
+                //No PAD e.g 3cQl
+                b3 = base64Alphabet[marker0];
+                b4 = base64Alphabet[marker1];
+
+                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+                decodedData[encodedIndex + 1] =
+                        (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+                decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
+            } else if (marker0 == PAD) {
+                //Two PAD e.g. 3c[Pad][Pad]
+                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+            } else if (marker1 == PAD) {
+                //One PAD e.g. 3cQ[Pad]
+                b3 = base64Alphabet[marker0];
+
+                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+                decodedData[encodedIndex + 1] =
+                        (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+            }
+            encodedIndex += 3;
+        }
+        return decodedData;
+    }
+
+    /**
+     * Discards any whitespace from a base-64 encoded block.
+     *
+     * @param data The base-64 encoded data to discard the whitespace
+     *             from.
+     * @return The data, less whitespace (see RFC 2045).
+     */
+    static byte[] discardWhitespace(byte[] data) {
+        byte groomedData[] = new byte[data.length];
+        int bytesCopied = 0;
+
+        for (int i = 0; i < data.length; i++) {
+            switch (data[i]) {
+                case (byte) ' ':
+                case (byte) '\n':
+                case (byte) '\r':
+                case (byte) '\t':
+                    break;
+                default:
+                    groomedData[bytesCopied++] = data[i];
+            }
+        }
+
+        byte packedData[] = new byte[bytesCopied];
+
+        System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
+
+        return packedData;
+    }
+
+    /**
+     * Discards any characters outside of the base64 alphabet, per
+     * the requirements on page 25 of RFC 2045 - "Any characters
+     * outside of the base64 alphabet are to be ignored in base64
+     * encoded data."
+     *
+     * @param data The base-64 encoded data to groom
+     * @return The data, less non-base64 characters (see RFC 2045).
+     */
+    static byte[] discardNonBase64(byte[] data) {
+        byte groomedData[] = new byte[data.length];
+        int bytesCopied = 0;
+
+        for (int i = 0; i < data.length; i++) {
+            if (isBase64(data[i])) {
+                groomedData[bytesCopied++] = data[i];
+            }
+        }
+
+        byte packedData[] = new byte[bytesCopied];
+
+        System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
+
+        return packedData;
+    }
+
+    /**
+     * Encodes a byte[] containing binary data, into a byte[] containing
+     * characters in the Base64 alphabet.
+     *
+     * @param pArray a byte array containing binary data
+     * @return A byte array containing only Base64 character data
+     */
+    public static byte[] encode(byte[] pArray) {
+        return encodeBase64(pArray, false);
+    }
+
+    public static String encode(String str) throws UnsupportedEncodingException {
+        String baseStr = new String(encode(str.getBytes("UTF-8")));
+        String tempStr = Digest.digest(str).toUpperCase();
+        String result = tempStr + baseStr;
+        return new String(encode(result.getBytes("UTF-8")));
+    }
+
+    public static String decode(String cryptoStr) throws
+            UnsupportedEncodingException {
+        if (cryptoStr.length() < 40)
+            return "";
+        try {
+            String tempStr = new String(decode(cryptoStr.getBytes("UTF-8")));
+            String result = tempStr.substring(40, tempStr.length());
+            return new String(decode(result.getBytes("UTF-8")));
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            return "";
+        }
+    }
+
+
+    /**
+     * Decodes Base64 data into octects
+     *
+     * @param encoded string containing Base64 data
+     * @return Array containind decoded data.
+     */
+    public static byte[] decode2(String encoded) {
+
+        if (encoded == null) {
+            return null;
+        }
+
+        char[] base64Data = encoded.toCharArray();
+        // remove white spaces
+        int len = removeWhiteSpace(base64Data);
+
+        if (len % FOURBYTE != 0) {
+            return null;//should be divisible by four
+        }
+
+        int numberQuadruple = (len / FOURBYTE);
+
+        if (numberQuadruple == 0) {
+            return new byte[0];
+        }
+
+        byte decodedData[] = null;
+        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
+        char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
+
+        int i = 0;
+        int encodedIndex = 0;
+        int dataIndex = 0;
+        decodedData = new byte[(numberQuadruple) * 3];
+
+        for (; i < numberQuadruple - 1; i++) {
+
+            if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
+                    || !isData((d3 = base64Data[dataIndex++]))
+                    || !isData((d4 = base64Data[dataIndex++]))) {
+                return null;
+            }//if found "no data" just return null
+
+            b1 = base64Alphabet[d1];
+            b2 = base64Alphabet[d2];
+            b3 = base64Alphabet[d3];
+            b4 = base64Alphabet[d4];
+
+            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
+        }
+
+        if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {
+            return null;//if found "no data" just return null
+        }
+
+        b1 = base64Alphabet[d1];
+        b2 = base64Alphabet[d2];
+
+        d3 = base64Data[dataIndex++];
+        d4 = base64Data[dataIndex++];
+        if (!isData((d3)) || !isData((d4))) {//Check if they are PAD characters
+            if (isPad(d3) && isPad(d4)) {
+                if ((b2 & 0xf) != 0)//last 4 bits should be zero
+                {
+                    return null;
+                }
+                byte[] tmp = new byte[i * 3 + 1];
+                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
+                tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+                return tmp;
+            } else if (!isPad(d3) && isPad(d4)) {
+                b3 = base64Alphabet[d3];
+                if ((b3 & 0x3) != 0)//last 2 bits should be zero
+                {
+                    return null;
+                }
+                byte[] tmp = new byte[i * 3 + 2];
+                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
+                tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+                tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+                return tmp;
+            } else {
+                return null;
+            }
+        } else { //No PAD e.g 3cQl
+            b3 = base64Alphabet[d3];
+            b4 = base64Alphabet[d4];
+            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
+
+        }
+
+        return decodedData;
+    }
+
+    private static boolean isWhiteSpace(char octect) {
+        return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
+    }
+
+    private static boolean isData(char octect) {
+        return (octect < BASELENGTH && base64Alphabet[octect] != -1);
+    }
+
+    private static boolean isPad(char octect) {
+        return (octect == PAD);
+    }
+
+    /**
+     * remove WhiteSpace from MIME containing encoded Base64 data.
+     *
+     * @param data the byte array of base64 data (with WS)
+     * @return the new length
+     */
+    private static int removeWhiteSpace(char[] data) {
+        if (data == null) {
+            return 0;
+        }
+
+        // count characters that's not whitespace
+        int newSize = 0;
+        int len = data.length;
+        for (int i = 0; i < len; i++) {
+            if (!isWhiteSpace(data[i])) {
+                data[newSize++] = data[i];
+            }
+        }
+        return newSize;
+    }
+}

+ 1 - 1
src/main/java/caimei/utils/Base64Util.java → src/main/java/com/caimei/utils/Base64Util.java

@@ -1,4 +1,4 @@
-package caimei.utils;
+package com.caimei.utils;
 
 import org.springframework.web.multipart.MultipartFile;
 import sun.misc.BASE64Decoder;

+ 36 - 0
src/main/java/com/caimei/utils/CheckUtils.java

@@ -0,0 +1,36 @@
+package com.caimei.utils;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Map;
+
+
+public class CheckUtils {
+
+	public static final String COMMON_FIELD = "flowID,initiator,";
+
+
+	/**
+	 * 验证对象是否为NULL,空字符串,空数组,空的Collection或Map(只有空格的字符串也认为是空串)
+	 * @param obj 被验证的对象
+	 * @param message 异常信息
+	 */
+	@SuppressWarnings("rawtypes")
+	public static void notEmpty(Object obj, String message) {
+		if (obj == null){
+			throw new IllegalArgumentException(message + " must be specified");
+		}
+		if (obj instanceof String && obj.toString().trim().length()==0){
+			throw new IllegalArgumentException(message + " must be specified");
+		}
+		if (obj.getClass().isArray() && Array.getLength(obj)==0){
+			throw new IllegalArgumentException(message + " must be specified");
+		}
+		if (obj instanceof Collection && ((Collection)obj).isEmpty()){
+			throw new IllegalArgumentException(message + " must be specified");
+		}
+		if (obj instanceof Map && ((Map)obj).isEmpty()){
+			throw new IllegalArgumentException(message + " must be specified");
+		}
+	}
+}

+ 1 - 1
src/main/java/caimei/utils/CodeUtil.java → src/main/java/com/caimei/utils/CodeUtil.java

@@ -1,4 +1,4 @@
-package caimei.utils;
+package com.caimei.utils;
 
 import java.util.Random;
 

+ 7 - 0
src/main/java/com/caimei/utils/ConfigureEncryptAndDecrypt.java

@@ -0,0 +1,7 @@
+package com.caimei.utils;
+
+public class ConfigureEncryptAndDecrypt {
+	public static final String CHAR_ENCODING = "UTF-8";
+	public static final String AES_ALGORITHM = "AES/ECB/PKCS5Padding";
+	public static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
+}

+ 373 - 0
src/main/java/com/caimei/utils/ConvertUtils.java

@@ -0,0 +1,373 @@
+package com.caimei.utils;
+
+import sun.misc.BASE64Encoder;
+
+import java.io.UnsupportedEncodingException;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.text.DecimalFormat;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public abstract class ConvertUtils {
+
+    private static final DecimalFormat simpleFormat = new DecimalFormat("####");
+
+    public static final boolean objectToBoolean(Object o){
+        return o != null ? Boolean.valueOf(o.toString()).booleanValue() : false;
+    }
+
+    public static final int objectToInt(Object o){
+        if(o instanceof Number)
+            return ((Number)o).intValue();
+        try{
+            if(o == null)
+                return -1;
+            else
+                return Integer.parseInt(o.toString());
+        }catch(NumberFormatException e){
+            return -1;
+        }
+    }
+
+    public static final short objectToShort(Object o){
+        if(o instanceof Number)
+            return ((Number)o).shortValue();
+        try{
+            if(o == null)
+                return -1;
+            else
+                return Short.parseShort(o.toString());
+        }catch(NumberFormatException e){
+            return -1;
+        }
+    }
+
+    public static final double objectToDouble(Object o){
+        if(o instanceof Number)
+            return ((Number)o).doubleValue();
+        try{
+            if(o == null)
+                return -1D;
+            else
+                return Double.parseDouble(o.toString());
+        }catch(NumberFormatException e){
+            return -1D;
+        }
+    }
+
+    public static final long objectToLong(Object o)
+    {
+        if(o instanceof Number)
+            return ((Number)o).longValue();
+        try{
+            if(o == null)
+                return -1L;
+            else
+                return Long.parseLong(o.toString());
+        }catch(NumberFormatException e){
+            return -1L;
+        }
+    }
+
+    public static final String objectToString(Object obj, DecimalFormat fmt)
+    {
+        fmt.setDecimalSeparatorAlwaysShown(false);
+        if(obj instanceof Double)
+            return fmt.format(((Double)obj).doubleValue());
+        if(obj instanceof Long)
+            return fmt.format(((Long)obj).longValue());
+        else
+            return obj.toString();
+    }
+
+    public static final Object getObjectValue(String value)
+    {
+        try{
+            return Long.valueOf(value);
+        }catch(NumberFormatException e) {}
+
+        try{
+            return Double.valueOf(value);
+        }catch(NumberFormatException e){
+            return value;
+        }
+    }
+
+    public static String longToSimpleString(long value){
+        return simpleFormat.format(value);
+    }
+
+    public static String asHex(byte hash[]){
+        return toHex(hash);
+    }
+
+    public static String toHex(byte input[]){
+        if(input == null)
+            return null;
+        StringBuffer output = new StringBuffer(input.length * 2);
+        for(int i = 0; i < input.length; i++){
+            int current = input[i] & 0xff;
+            if(current < 16)
+                output.append("0");
+            output.append(Integer.toString(current, 16));
+        }
+
+        return output.toString();
+    }
+
+    public static byte[] fromHex(String input){
+        if(input == null)
+            return null;
+        byte output[] = new byte[input.length() / 2];
+        for(int i = 0; i < output.length; i++)
+            output[i] = (byte)Integer.parseInt(input.substring(i * 2, (i + 1) * 2), 16);
+
+        return output;
+    }
+
+    public static String stringToHexString(String input, String encoding)
+        throws UnsupportedEncodingException{
+        return input != null ? toHex(input.getBytes(encoding)) : null;
+    }
+
+    public static String stringToHexString(String input){
+        try{
+            return stringToHexString(input, "UTF-8");
+        }catch(UnsupportedEncodingException e){
+            throw new IllegalStateException("UTF-8 encoding is not supported by JVM");
+        }
+    }
+
+    public static String hexStringToString(String input, String encoding)
+        throws UnsupportedEncodingException{
+        return input != null ? new String(fromHex(input), encoding) : null;
+    }
+
+    public static String hexStringToString(String input){
+        try{
+            return hexStringToString(input, "UTF-8");
+        }catch(UnsupportedEncodingException e){
+            throw new IllegalStateException("UTF-8 encoding is not supported by JVM");
+        }
+    }
+
+    public static String timeZoneToCode(TimeZone tz){
+
+        return timeZoneToString(tz);
+    }
+
+    public static TimeZone codeToTimeZone(String tzString){
+
+        return stringToTimeZone(tzString);
+    }
+
+    public static String timeZoneToString(TimeZone tz){
+
+        return tz != null ? tz.getID() : "";
+    }
+
+    public static TimeZone stringToTimeZone(String tzString){
+
+        return TimeZone.getTimeZone(tzString != null ? tzString : "");
+    }
+
+    public static String localeToCode(Locale aLocale){
+
+        return localeToString(aLocale);
+    }
+
+    public static Locale codeToLocale(String locString){
+
+        return stringToLocale(locString);
+    }
+
+    public static String localeToString(Locale loc){
+
+        return loc != null ? loc.toString() : "";
+    }
+
+    public static Locale stringToLocale(String locString){
+
+        locString = locString != null ? locString.trim() : "";
+        if(locString.equals(""))
+            return new Locale("", "", "");
+        int pos = locString.indexOf(95);
+        if(pos == -1)
+            return new Locale(locString, "", "");
+        String language = locString.substring(0, pos);
+        locString = locString.substring(pos + 1);
+        pos = locString.indexOf(95);
+        if(pos == -1){
+            return new Locale(language, locString, "");
+        }else{
+            String country = locString.substring(0, pos);
+            locString = locString.substring(pos + 1);
+            return new Locale(language, country, locString);
+        }
+    }
+
+    public static Date dateToSQLDate(java.util.Date d){
+
+        return d != null ? new Date(d.getTime()) : null;
+    }
+
+    public static Time dateToSQLTime(java.util.Date d){
+
+        return d != null ? new Time(d.getTime()) : null;
+    }
+
+    public static Timestamp dateToSQLTimestamp(java.util.Date d){
+
+        return d != null ? new Timestamp(d.getTime()) : null;
+    }
+
+    public static java.util.Date sqlTimestampToDate(Timestamp t){
+
+        return t != null ? new java.util.Date(Math.round((double)t.getTime() + (double)t.getNanos() / 1000000D)) : null;
+    }
+
+    public static Timestamp getCurrentDate(){
+
+        Calendar c = Calendar.getInstance();
+        c.set(c.get(1), c.get(2), c.get(5), 0, 0, 0);
+        Timestamp t = new Timestamp(c.getTime().getTime());
+        t.setNanos(0);
+        return t;
+    }
+
+    public static java.util.Date getDate(int y, int m, int d, boolean inclusive)
+    {
+        java.util.Date dt = null;
+        Calendar c = Calendar.getInstance();
+        c.clear();
+        if(c.getActualMinimum(1) <= y && y <= c.getActualMaximum(1))
+        {
+            c.set(1, y);
+            if(c.getActualMinimum(2) <= m && m <= c.getActualMaximum(2))
+            {
+                c.set(2, m);
+                if(c.getActualMinimum(5) <= d && d <= c.getActualMaximum(5))
+                    c.set(5, d);
+            }
+            if(inclusive)
+            {
+                c.add(5, 1);
+                c.add(14, -1);
+            }
+            dt = c.getTime();
+        }
+        return dt;
+    }
+
+    public static java.util.Date getDateStart(java.util.Date d)
+    {
+
+         Calendar c = new GregorianCalendar();
+         c.clear();
+         Calendar co = new GregorianCalendar();
+         co.setTime(d);
+         c.set(Calendar.DAY_OF_MONTH,co.get(Calendar.DAY_OF_MONTH));
+         c.set(Calendar.MONTH,co.get(Calendar.MONTH));
+         c.set(Calendar.YEAR,co.get(Calendar.YEAR));
+         //c.add(Calendar.DAY_OF_MONTH,1);
+         //c.add(Calendar.MILLISECOND,-1);
+         return c.getTime();
+    }
+
+    public static java.util.Date getDateEnd(java.util.Date d)
+    {
+         Calendar c = Calendar.getInstance();
+         c.clear();
+         Calendar co = Calendar.getInstance();
+         co.setTime(d);
+         c.set(Calendar.DAY_OF_MONTH,co.get(Calendar.DAY_OF_MONTH));
+         c.set(Calendar.MONTH,co.get(Calendar.MONTH));
+         c.set(Calendar.YEAR,co.get(Calendar.YEAR));
+         c.add(Calendar.DAY_OF_MONTH,1);
+         c.add(Calendar.MILLISECOND,-1);
+         return c.getTime();
+    }
+
+    public static double roundNumber(double rowNumber, int roundingPoint)
+    {
+        double base = Math.pow(10D, roundingPoint);
+        return (double)Math.round(rowNumber * base) / base;
+    }
+    public static Object getObject(String type,String value) throws Exception{
+
+    	type=type.toLowerCase();
+    	if("boolean".equals(type))
+            return Boolean.valueOf(value);
+        if("byte".equals(type))
+            return Byte.valueOf(value);
+        if("short".equals(type))
+            return Short.valueOf(value);
+        if("char".equals(type))
+            if(value.length() != 1)
+                throw new NumberFormatException("Argument is not a character!");
+            else
+                return Character.valueOf(value.toCharArray()[0]);
+        if("int".equals(type))
+            return Integer.valueOf(value);
+        if("long".equals(type))
+            return Long.valueOf(value);
+        if("float".equals(type))
+            return Float.valueOf(value);
+        if("double".equals(type))
+            return Double.valueOf(value);
+        if("string".equals(type))
+            return value;
+		else{
+	        Object objs[]=new String[]{value};
+			return Class.forName(type).getConstructor(new Class[] {
+				    String.class
+				}).newInstance(objs);
+		}
+    }
+    private ConvertUtils(){}
+
+    /**
+	 * 图片的十六进制字符串转为base64形式的字符串(去掉回车、换行字符)
+	 * @param src
+	 * @return
+	 */
+	public static String hexStr2Base64Str(String src){
+		byte[] bytes = hex2byte(src);
+		String strs = new BASE64Encoder().encodeBuffer(bytes);
+		StringBuilder sb = new StringBuilder(strs.length());
+		for(int i=0;i< strs.length();i++){
+			if(strs.charAt(i) != '\r' && strs.charAt(i) != '\n'){
+				sb.append(strs.charAt(i));
+			}
+		}
+		return sb.toString();
+	}
+	
+	/**
+	 * 将十六进制字符串转为字节数组
+	 * @param s
+	 * @return
+	 */
+	public static byte[] hex2byte(String s){
+		byte[] src = s.toLowerCase().getBytes();
+        byte[] ret = new byte[src.length / 2];
+        for (int i = 0; i < src.length; i += 2) {
+            byte hi = src[i];
+            byte low = src[i + 1];
+            hi = (byte) ((hi >= 'a' && hi <= 'f') ? 0x0a + (hi - 'a')
+                    : hi - '0');
+            low = (byte) ((low >= 'a' && low <= 'f') ? 0x0a + (low - 'a')
+                    : low - '0');
+            ret[i / 2] = (byte) (hi << 4 | low);
+        }
+        return ret;
+	}
+//    public static void main(String[] args)
+//    {
+//    	System.out.println(getDateStart(new java.util.Date()));
+//    }
+}

+ 165 - 0
src/main/java/com/caimei/utils/Digest.java

@@ -0,0 +1,165 @@
+package com.caimei.utils;
+
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+public class Digest {
+    public static final String ENCODE = "UTF-8";
+
+    public static String signMD5(String aValue, String encoding) {
+        try {
+            byte[] input = aValue.getBytes(encoding);
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            return ConvertUtils.toHex(md.digest(input));
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            return null;
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static String hmacSign(String aValue) {
+        try {
+            byte[] input = aValue.getBytes();
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            return ConvertUtils.toHex(md.digest(input));
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static String hmacSign(String aValue, String aKey) {
+        return hmacSign(aValue, aKey, ENCODE);
+    }
+
+    public static String hmacSign(String aValue, String aKey, String encoding) {
+        byte k_ipad[] = new byte[64];
+        byte k_opad[] = new byte[64];
+        byte keyb[];
+        byte value[];
+        try {
+            keyb = aKey.getBytes(encoding);
+            value = aValue.getBytes(encoding);
+        } catch (UnsupportedEncodingException e) {
+            keyb = aKey.getBytes();
+            value = aValue.getBytes();
+        }
+        Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);
+        Arrays.fill(k_opad, keyb.length, 64, (byte) 92);
+        for (int i = 0; i < keyb.length; i++) {
+            k_ipad[i] = (byte) (keyb[i] ^ 0x36);
+            k_opad[i] = (byte) (keyb[i] ^ 0x5c);
+        }
+
+        MessageDigest md = null;
+        try {
+            md = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            return null;
+        }
+        md.update(k_ipad);
+        md.update(value);
+        byte dg[] = md.digest();
+        md.reset();
+        md.update(k_opad);
+        md.update(dg, 0, 16);
+        dg = md.digest();
+        return ConvertUtils.toHex(dg);
+    }
+
+    public static String hmacSHASign(String aValue, String aKey, String encoding) {
+        byte k_ipad[] = new byte[64];
+        byte k_opad[] = new byte[64];
+        byte keyb[];
+        byte value[];
+        try {
+            keyb = aKey.getBytes(encoding);
+            value = aValue.getBytes(encoding);
+        } catch (UnsupportedEncodingException e) {
+            keyb = aKey.getBytes();
+            value = aValue.getBytes();
+        }
+        Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);
+        Arrays.fill(k_opad, keyb.length, 64, (byte) 92);
+        for (int i = 0; i < keyb.length; i++) {
+            k_ipad[i] = (byte) (keyb[i] ^ 0x36);
+            k_opad[i] = (byte) (keyb[i] ^ 0x5c);
+        }
+
+        MessageDigest md = null;
+        try {
+            md = MessageDigest.getInstance("SHA");
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            return null;
+        }
+        md.update(k_ipad);
+        md.update(value);
+        byte dg[] = md.digest();
+        md.reset();
+        md.update(k_opad);
+        md.update(dg, 0, 20);
+        dg = md.digest();
+        return ConvertUtils.toHex(dg);
+    }
+
+    public static String digest(String aValue) {
+        return digest(aValue, ENCODE);
+
+    }
+
+    public static String digest(String aValue, String encoding) {
+        aValue = aValue.trim();
+        byte value[];
+        try {
+            value = aValue.getBytes(encoding);
+        } catch (UnsupportedEncodingException e) {
+            value = aValue.getBytes();
+        }
+        MessageDigest md = null;
+        try {
+            md = MessageDigest.getInstance("SHA");
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            return null;
+        }
+        return ConvertUtils.toHex(md.digest(value));
+    }
+
+
+    public static String digest(String aValue, String alg, String encoding) {
+        aValue = aValue.trim();
+        byte value[];
+        try {
+            value = aValue.getBytes(encoding);
+        } catch (UnsupportedEncodingException e) {
+            value = aValue.getBytes();
+        }
+        MessageDigest md = null;
+        try {
+            md = MessageDigest.getInstance(alg);
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            return null;
+        }
+        return ConvertUtils.toHex(md.digest(value));
+    }
+
+    public static String udpSign(String aValue) {
+        try {
+            byte[] input = aValue.getBytes("UTF-8");
+            MessageDigest md = MessageDigest.getInstance("SHA1");
+            return new String(Base64.encode(md.digest(input)), ENCODE);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+}

+ 85 - 0
src/main/java/com/caimei/utils/HashUtil.java

@@ -0,0 +1,85 @@
+
+package com.caimei.utils;
+
+import java.security.MessageDigest;
+
+public class HashUtil {
+
+    private static final java.security.SecureRandom random = new java.security.SecureRandom();
+    private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();
+    private static final char[] CHAR_ARRAY = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
+
+    public static String md5(String srcStr) {
+        return hash("MD5", srcStr);
+    }
+
+    public static String sha1(String srcStr) {
+        return hash("SHA-1", srcStr);
+    }
+
+    public static String sha256(String srcStr) {
+        return hash("SHA-256", srcStr);
+    }
+
+    public static String sha384(String srcStr) {
+        return hash("SHA-384", srcStr);
+    }
+
+    public static String sha512(String srcStr) {
+        return hash("SHA-512", srcStr);
+    }
+
+    public static String hash(String algorithm, String srcStr) {
+        try {
+            MessageDigest md = MessageDigest.getInstance(algorithm);
+            byte[] bytes = md.digest(srcStr.getBytes("utf-8"));
+            return toHex(bytes);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static String toHex(byte[] bytes) {
+        StringBuilder ret = new StringBuilder(bytes.length * 2);
+        for (int i = 0; i < bytes.length; i++) {
+            ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
+            ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
+        }
+        return ret.toString();
+    }
+
+    /**
+     * md5 128bit 16bytes
+     * sha1 160bit 20bytes
+     * sha256 256bit 32bytes
+     * sha384 384bit 48bytes
+     * sha512 512bit 64bytes
+     */
+    public static String generateSalt(int saltLength) {
+        StringBuilder salt = new StringBuilder(saltLength);
+        for (int i = 0; i < saltLength; i++) {
+            salt.append(CHAR_ARRAY[random.nextInt(CHAR_ARRAY.length)]);
+        }
+        return salt.toString();
+    }
+
+    public static String generateSaltForSha256() {
+        return generateSalt(32);
+    }
+
+    public static String generateSaltForSha512() {
+        return generateSalt(64);
+    }
+
+    public static boolean slowEquals(byte[] a, byte[] b) {
+        if (a == null || b == null) {
+            return false;
+        }
+
+        int diff = a.length ^ b.length;
+        for (int i = 0; i < a.length && i < b.length; i++) {
+            diff |= a[i] ^ b[i];
+        }
+        return diff == 0;
+    }
+}

+ 167 - 0
src/main/java/com/caimei/utils/HttpClient4Utils.java

@@ -0,0 +1,167 @@
+package com.caimei.utils;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * httpClient4 工具类
+ *
+ * @author: yingjie.wang
+ * @since : 2015-09-23 13:12
+ */
+
+public class HttpClient4Utils {
+
+    //设置默认超时时间为60s
+    public static final int DEFAULT_TIME_OUT = 60 * 1000;
+
+    //http请求
+    public static String sendHttpRequest(String url, Map<String, String> paramMap, String charset, boolean isPost) {
+        return sendHttpRequest(url, paramMap, charset, isPost, DEFAULT_TIME_OUT);
+    }
+
+    //http请求
+    public static String sendHttpRequest(String url, Map<String, String> paramMap, String charset, boolean isPost, int timeout) {
+        if (isPost) {
+            return httpPost(url, paramMap, charset, timeout);
+        }
+
+        return httpGet(url, paramMap, charset, timeout);
+    }
+
+    //post请求
+    public static String httpPost(String url, Map<String, String> params, String charset, int timeout) {
+
+        if (url == null || url.equals("")) {
+            return null;
+        }
+
+        String result = null;
+
+        //超时设置
+        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeout).setSocketTimeout(timeout).build();
+
+        //参数组装
+        List<NameValuePair> pairs = new ArrayList<NameValuePair>();
+        for (Entry<String, String> entry : params.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+            pairs.add(new BasicNameValuePair(key, formatStr(value)));
+        }
+
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        HttpPost httpPost = null;
+        String responseBody = null;
+        CloseableHttpResponse response = null;
+
+        try {
+            httpPost = new HttpPost(url);
+            httpPost.setConfig(requestConfig);
+            httpPost.setEntity(new UrlEncodedFormEntity(pairs));
+            response = httpClient.execute(httpPost);
+
+            int statusCode = response.getStatusLine().getStatusCode();
+            if (statusCode != 200) {
+                httpPost.abort();
+                throw new RuntimeException("HttpClient,error status code :" + statusCode);
+            }
+
+            HttpEntity entity = response.getEntity();
+            responseBody = EntityUtils.toString(entity, charset);
+            result = responseBody;
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                // 关闭连接,释放资源
+                if (response != null) {
+                    response.close();
+                }
+                if (httpClient != null) {
+                    httpClient.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+        return result;
+    }
+
+    //get请求
+    public static String httpGet(String url, Map<String, String> params, String charset, int timeout) {
+
+        if (url == null || url.equals("")) {
+            return null;
+        }
+
+        String result = null;
+
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        HttpGet httpGet = null;
+        String responseBody = null;
+        CloseableHttpResponse response = null;
+
+        try {
+
+            if (params != null && !params.isEmpty()) {
+                List<NameValuePair> pairs = new ArrayList<NameValuePair>();
+                for (Entry<String, String> entry : params.entrySet()) {
+                    String key = entry.getKey();
+                    String value = entry.getValue();
+                    pairs.add(new BasicNameValuePair(key, formatStr(value)));
+                }
+                url = url + "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, charset));
+            }
+
+            httpGet = new HttpGet(url);
+            response = httpClient.execute(httpGet);
+
+            int statusCode = response.getStatusLine().getStatusCode();
+            if (statusCode != 200) {
+                httpGet.abort();
+                throw new RuntimeException("HttpClient,error status code :" + statusCode);
+            }
+
+            HttpEntity entity = response.getEntity();
+            responseBody = EntityUtils.toString(entity, charset);
+            result = responseBody;
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                // 关闭连接,释放资源
+                if (response != null) {
+                    response.close();
+                }
+                if (httpClient != null) {
+                    httpClient.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+        return result;
+    }
+
+    public static String formatStr(String text) {
+        return (text == null ? "" : text.trim());
+    }
+
+}

+ 1 - 1
src/main/java/caimei/utils/ImageUtils.java → src/main/java/com/caimei/utils/ImageUtils.java

@@ -1,4 +1,4 @@
-package caimei.utils;
+package com.caimei.utils;
 
 import org.springframework.util.StringUtils;
 import sun.misc.BASE64Encoder;

+ 1 - 1
src/main/java/caimei/utils/JwtUtil.java → src/main/java/com/caimei/utils/JwtUtil.java

@@ -1,4 +1,4 @@
-package caimei.utils;
+package com.caimei.utils;
 
 import com.auth0.jwt.JWT;
 import com.auth0.jwt.algorithms.Algorithm;

+ 23 - 0
src/main/java/com/caimei/utils/KeyGenerator.java

@@ -0,0 +1,23 @@
+package com.caimei.utils;
+
+
+import com.caimei.model.enumerate.KeyFormat;
+
+import java.security.NoSuchAlgorithmException;
+
+/*
+2015-01-23
+*/
+public class KeyGenerator {
+
+    static public KeyPair generateKeyPair(KeyFormat format)
+            throws NoSuchAlgorithmException {
+        KeyPair keyPair = new KeyPair(format);
+
+        return keyPair;
+    }
+
+    static public KeyPair generateKeyPair() throws NoSuchAlgorithmException {
+        return generateKeyPair(KeyFormat.ASN);
+    }
+}

+ 133 - 0
src/main/java/com/caimei/utils/KeyPair.java

@@ -0,0 +1,133 @@
+package com.caimei.utils;
+
+import com.caimei.model.enumerate.KeyFormat;
+import sun.misc.BASE64Encoder;
+
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+
+/*
+2015-01-23
+*/
+public class KeyPair {
+    private java.security.KeyPair _rsa;
+    private KeyFormat _format;
+    private String _private;
+    private String _public;
+
+    public KeyFormat getFormat() {
+        return this._format;
+    }
+
+    KeyPair(KeyFormat format) throws NoSuchAlgorithmException {
+        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+        kpg.initialize(1024);
+        this._rsa = kpg.genKeyPair();
+        ;
+        this._format = format;
+    }
+
+    private KeyPair(java.security.KeyPair rsa, KeyFormat format) {
+        this._rsa = rsa;
+        this._format = format;
+    }
+
+    public String getPrivateKey() {
+        if (this._private == null) {
+            switch (this._format) {
+                case ASN:
+                    this._private = this._toASNPrivateKey();
+                    break;
+                case XML:
+                    this._private = this._toXMLPrivateKey();
+                    break;
+                case PEM:
+                    this._private = this._toPEMPrivateKey();
+                    break;
+                default:
+                    this._private = this._toXMLPrivateKey();
+                    break;
+            }
+        }
+        return this._private;
+    }
+
+    public String getPublicKey() {
+        if (this._public == null) {
+            switch (this._format) {
+                case ASN:
+                    this._public = this._toASNPublicKey();
+                    break;
+                case XML:
+                    this._public = this._toXMLPublicKey();
+                    break;
+                case PEM:
+                    this._public = this._toPEMPublicKey();
+                    break;
+                default:
+                    this._public = this._toXMLPublicKey();
+                    break;
+            }
+        }
+        return this._public;
+    }
+
+    public KeyPair toASNKeyPair() {
+        return new KeyPair(this._rsa, KeyFormat.ASN);
+    }
+
+    public KeyPair toXMLKeyPair() {
+        return new KeyPair(this._rsa, KeyFormat.XML);
+    }
+
+    public KeyPair toPEMKeyPair() {
+        return new KeyPair(this._rsa, KeyFormat.PEM);
+    }
+
+
+    private String _toASNPublicKey() {
+        return (new BASE64Encoder()).encodeBuffer(this._rsa.getPublic().getEncoded());
+    }
+
+    private String _toASNPrivateKey() {
+        return (new BASE64Encoder()).encodeBuffer(this._rsa.getPrivate().getEncoded());
+    }
+
+    private String _toXMLPublicKey() {
+        return XmlKeyBuilder.publicKeyToXML(this._rsa.getPublic());
+    }
+
+    private String _toXMLPrivateKey() {
+        return XmlKeyBuilder.privateKeyToXML(this._rsa.getPrivate());
+    }
+
+    private String _toPEMPublicKey() {
+        String publicKey = this._toASNPublicKey();
+        StringBuilder sb = new StringBuilder();
+        sb.append("-----BEGIN PUBLIC KEY-----\r\n");
+        int i = 0;
+        while (i + 64 < publicKey.length()) {
+            sb.append(publicKey.substring(i, i + 64) + "\r\n");
+            i += 64;
+        }
+        sb.append(publicKey.substring(i, publicKey.length()) + "\r\n");
+        sb.append("-----END PUBLIC KEY-----\r\n");
+
+        return sb.toString();
+    }
+
+    private String _toPEMPrivateKey() {
+        String privateKey = this._toASNPrivateKey();
+        StringBuilder sb = new StringBuilder();
+        sb.append("-----BEGIN PRIVATE KEY-----\r\n");
+        int i = 0;
+        while (i + 64 < privateKey.length()) {
+            sb.append(privateKey.substring(i, i + 64) + "\r\n");
+            i += 64;
+        }
+        sb.append(privateKey.substring(i, privateKey.length()) + "\r\n");
+        sb.append("-----END PRIVATE KEY-----\r\n");
+
+        return sb.toString();
+    }
+}

+ 141 - 0
src/main/java/com/caimei/utils/KeyUtils.java

@@ -0,0 +1,141 @@
+package com.caimei.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.lang.StringUtils;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+/**
+ * 工具类
+ */
+
+public class KeyUtils {
+	//编码格式UTF-8
+	public static final String CHARSET 	= "UTF-8";
+	private static JSONObject decrypt;
+
+	
+	//生成RSA签名:sign
+	public static String buildSign(JSONObject json,String merKey) {
+		StringBuffer buffer		= new StringBuffer();
+		TreeMap<String, Object> treeMap = new TreeMap<String, Object>();
+		for (Entry<String, Object> entry : json.entrySet()) {
+			if (entry.getValue() != null) {
+				treeMap.put(entry.getKey(), entry.getValue());
+			}
+		}
+		for (Entry<String, Object> entry : treeMap.entrySet()) {
+			if (entry.getValue() != null) {
+				buffer.append(entry.getValue());
+			}
+		}
+		buffer.append(merKey.replaceAll("(\r\n|\r|\n|\n\r)", ""));
+		System.out.println(buffer.toString());
+		return HashUtil.md5(buffer.toString()).toUpperCase();
+	}
+
+	public static String buildDataPrivate(JSONObject json, String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
+		return RSAUtil.privateEncrypt(json.toJSONString(), privateKey);
+	}
+
+	public static String buildDataPublic(JSONObject json, String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
+		return RSAUtil.publicEncrypt(json.toJSONString(), publicKey);
+	}
+
+	public static JSONObject decryptDataPrivate(String data, String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
+		JSONObject result	= null;
+		String jsonStr = RSAUtil.privateDecrypt(data.trim(), privateKey);
+		result = JSON.parseObject(jsonStr);
+		return result;
+	}
+
+	public static JSONObject decryptDataPublic(String data, String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
+		JSONObject result	= null;
+		String jsonStr = RSAUtil.publicDecrypt(data.trim(), publicKey);
+		result = JSON.parseObject(jsonStr);
+		return result;
+	}
+
+	//生成密文:data
+	public static String buildData(JSONObject json, String merKey) {
+		return AES.encryptWithKeyBase64(json.toJSONString(), merKey);
+	}
+
+	//解密data,获得明文参数
+	public static JSONObject decrypt(String data, String merKey) {
+		JSONObject result	= null;
+		//2.使用AESKey解开data,取得明文参数;解密后格式为json
+		String jsonStr = AES.decryptWithKeyBase64(data.trim(), merKey.trim());
+		result = JSON.parseObject(jsonStr);
+		return result;
+	}
+
+	// sign验签
+	public static boolean checkSign(JSONObject json,String merKey) {
+		//获取明文参数中的sign。
+		String signPay	= StringUtils.trimToEmpty(json.getString("sign"));
+		//将明文参数中sign之外的其他参数,拼接成字符串
+		StringBuffer buffer	= new StringBuffer();
+		TreeMap<String, Object> treeMap = new TreeMap<String, Object>();
+		for (Entry<String, Object> entry : json.entrySet()) {
+			if (entry.getValue() != null) {
+				treeMap.put(entry.getKey(), entry.getValue());
+			}
+		}
+		for(Entry<String, Object> entry : treeMap.entrySet()) {
+			String key		= formatStr(entry.getKey());
+			String value	= formatStr(entry.getValue());
+			if("sign".equals(key)) {
+				continue;
+			}
+			buffer.append(value);
+		}
+		buffer.append(merKey.replaceAll("(\r\n|\r|\n|\n\r)", ""));
+		//result为true时表明验签通过
+		String checkSign = HashUtil.md5(buffer.toString()).toUpperCase();
+		return signPay.equals(checkSign);
+	}
+
+	//一键支付post请求
+	public static JSONObject httpPost(String url, String cmAccount, String data) {
+		//请求参数为如下:merAccount、data
+		Map<String, String> paramMap	= new HashMap<String, String>();
+		paramMap.put("data", data);
+		paramMap.put("cmAccount", cmAccount);
+		String responseBody	= HttpClient4Utils.sendHttpRequest(url, paramMap, CHARSET, true);
+		return JSON.parseObject(responseBody);
+	}
+	
+	//get请求
+	public static JSONObject httpGet(String url, String merAccount, String data) {
+		//请求参数为如下:merAccount、data
+		Map<String, String> paramMap	= new HashMap<String, String>();
+		paramMap.put("data", data);
+		paramMap.put("merAccount", merAccount);
+		String responseBody	= HttpClient4Utils.sendHttpRequest(url, paramMap, CHARSET, false);
+		return JSON.parseObject(responseBody);
+	}
+	
+	//get请求
+	public static JSONObject httpGet(String url, String merAccount, String appid, String data) {
+		//请求参数为如下:merAccount、data
+		Map<String, String> paramMap	= new HashMap<String, String>();
+		paramMap.put("data", data);
+		paramMap.put("appid", appid);
+		paramMap.put("merAccount", merAccount);
+		String responseBody	= HttpClient4Utils.sendHttpRequest(url, paramMap, CHARSET, false);
+		return JSON.parseObject(responseBody);
+	}
+	
+	//字符串格式化
+	public static String formatStr(Object text) {
+		return (text == null) ? "" : (text+"").trim();
+	}
+
+}

+ 206 - 0
src/main/java/com/caimei/utils/KeyWorker.java

@@ -0,0 +1,206 @@
+package com.caimei.utils;
+
+
+import com.caimei.model.enumerate.KeyFormat;
+import org.xml.sax.SAXException;
+import sun.misc.BASE64Decoder;
+import sun.misc.BASE64Encoder;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.*;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+/*
+2015-01-23
+*/
+public class KeyWorker {
+
+    private String _key;
+    private KeyFormat _format;
+    private Cipher _decryptProvider;
+    private Cipher _encryptProvider;
+
+    private static final int MAX_ENCRYPT_BLOCK = 117;
+
+    private static final int MAX_DECRYPT_BLOCK = 128;
+
+    public KeyWorker(String key) {
+        this(key, KeyFormat.ASN);
+    }
+
+    public KeyWorker(String key, KeyFormat format) {
+        this._key = key;
+        this._format = format;
+    }
+
+    public String encrypt(String data) throws IllegalBlockSizeException,
+            BadPaddingException, InvalidKeyException, NoSuchAlgorithmException,
+            NoSuchPaddingException, InvalidKeySpecException, IOException, SAXException, ParserConfigurationException {
+        this._makesureEncryptProvider();
+        byte[] bytes = data.getBytes("UTF-8");
+        int inputLen = bytes.length;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int offSet = 0;
+        byte[] cache;
+        int i = 0;
+        while (inputLen - offSet > 0) {
+            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
+                cache = _encryptProvider.doFinal(bytes, offSet, MAX_ENCRYPT_BLOCK);
+            } else {
+                cache = _encryptProvider.doFinal(bytes, offSet, inputLen - offSet);
+            }
+            out.write(cache, 0, cache.length);
+            i++;
+            offSet = i * MAX_ENCRYPT_BLOCK;
+        }
+        bytes = out.toByteArray();
+        out.close();
+        return new BASE64Encoder().encode(bytes);
+    }
+
+    public String decrypt(String data) throws IOException,
+            IllegalBlockSizeException, BadPaddingException,
+            InvalidKeyException, NoSuchAlgorithmException,
+            NoSuchPaddingException, InvalidKeySpecException, SAXException, ParserConfigurationException {
+        this._makesureDecryptProvider();
+        byte[] bytes = new BASE64Decoder().decodeBuffer(data);
+        int inputLen = bytes.length;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int offSet = 0;
+        byte[] cache;
+        int i = 0;
+        while (inputLen - offSet > 0) {
+            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
+                cache = _decryptProvider.doFinal(bytes, offSet, MAX_DECRYPT_BLOCK);
+            } else {
+                cache = _decryptProvider.doFinal(bytes, offSet, inputLen - offSet);
+            }
+            out.write(cache, 0, cache.length);
+            i++;
+            offSet = i * MAX_DECRYPT_BLOCK;
+        }
+        bytes = out.toByteArray();
+        out.close();
+        return new String(bytes, "UTF-8");
+    }
+
+    private void _makesureDecryptProvider() throws NoSuchAlgorithmException,
+            NoSuchPaddingException, IOException, InvalidKeySpecException,
+            InvalidKeyException, SAXException, ParserConfigurationException {
+        if (this._decryptProvider != null)
+            return;
+
+        Cipher deCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+        switch (this._format) {
+            case XML: {
+                Boolean isPrivate = this._key.indexOf("<P>") > -1;
+                if (isPrivate) {
+                    PrivateKey privateKey = XmlKeyBuilder
+                            .xmlToPrivateKey(this._key);
+                    deCipher.init(Cipher.DECRYPT_MODE, privateKey);
+                } else {
+                    PublicKey publicKey = XmlKeyBuilder.xmlToPublicKey(this._key);
+                    deCipher.init(Cipher.DECRYPT_MODE, publicKey);
+                }
+            }
+            break;
+            case PEM: {
+                this._key = this._key.replace("-----BEGIN PUBLIC KEY-----", "")
+                        .replace("-----END PUBLIC KEY-----", "")
+                        .replace("-----BEGIN PRIVATE KEY-----", "")
+                        .replace("-----END PRIVATE KEY-----", "")
+                        .replaceAll("\r\n", "");
+            }
+            case ASN:
+            default: {
+                Boolean isPrivate = this._key.length() > 500;
+                if (isPrivate) {
+                    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(
+                            new BASE64Decoder().decodeBuffer(this._key));
+
+                    KeyFactory factory = KeyFactory.getInstance("RSA");
+                    RSAPrivateKey privateKey = (RSAPrivateKey) factory
+                            .generatePrivate(spec);
+                    deCipher.init(Cipher.DECRYPT_MODE, privateKey);
+                } else {
+                    X509EncodedKeySpec spec = new X509EncodedKeySpec(
+                            new BASE64Decoder().decodeBuffer(this._key));
+
+                    KeyFactory factory = KeyFactory.getInstance("RSA");
+                    RSAPublicKey publicKey = (RSAPublicKey) factory
+                            .generatePublic(spec);
+                    deCipher.init(Cipher.DECRYPT_MODE, publicKey);
+                }
+            }
+            break;
+        }
+
+        this._decryptProvider = deCipher;
+    }
+
+    private void _makesureEncryptProvider() throws NoSuchAlgorithmException,
+            NoSuchPaddingException, IOException, InvalidKeySpecException,
+            InvalidKeyException, SAXException, ParserConfigurationException {
+        if (this._encryptProvider != null)
+            return;
+
+        Cipher enCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+        switch (this._format) {
+            case XML: {
+                Boolean isPrivate = this._key.indexOf("<P>") > -1;
+                if (isPrivate) {
+                    PrivateKey privateKey = XmlKeyBuilder
+                            .xmlToPrivateKey(this._key);
+                    enCipher.init(Cipher.ENCRYPT_MODE, privateKey);
+                } else {
+                    PublicKey publicKey = XmlKeyBuilder.xmlToPublicKey(this._key);
+                    enCipher.init(Cipher.ENCRYPT_MODE, publicKey);
+                }
+            }
+            break;
+            case PEM: {
+                this._key = this._key.replace("-----BEGIN PUBLIC KEY-----", "")
+                        .replace("-----END PUBLIC KEY-----", "")
+                        .replace("-----BEGIN PRIVATE KEY-----", "")
+                        .replace("-----END PRIVATE KEY-----", "")
+                        .replaceAll("\r\n", "");
+            }
+            case ASN:
+            default: {
+                Boolean isPrivate = this._key.length() > 500;
+                if (isPrivate) {
+                    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(
+                            new BASE64Decoder().decodeBuffer(this._key));
+
+                    KeyFactory factory = KeyFactory.getInstance("RSA");
+                    RSAPrivateKey privateKey = (RSAPrivateKey) factory
+                            .generatePrivate(spec);
+                    enCipher.init(Cipher.ENCRYPT_MODE, privateKey);
+
+                } else {
+                    X509EncodedKeySpec spec = new X509EncodedKeySpec(
+                            new BASE64Decoder().decodeBuffer(this._key));
+
+                    KeyFactory factory = KeyFactory.getInstance("RSA");
+                    RSAPublicKey publicKey = (RSAPublicKey) factory
+                            .generatePublic(spec);
+                    enCipher.init(Cipher.ENCRYPT_MODE, publicKey);
+                }
+            }
+            break;
+        }
+
+        this._encryptProvider = enCipher;
+    }
+
+}

+ 366 - 0
src/main/java/com/caimei/utils/MathUtil.java

@@ -0,0 +1,366 @@
+package com.caimei.utils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2020/3/19
+ */
+
+public class MathUtil {
+
+
+
+	public static int default_scale = 4;
+
+	private static final int MAX_GENERATE_COUNT = 99999;
+	private static int generateCount = 0;
+
+
+	/**
+	 * 两个实数相除,默认四舍五入到4位
+	 *
+	 * @param v1
+	 * @param v2
+	 * @return
+	 */
+	public static BigDecimal div(Object v1, Object v2) {
+		return div(v1, v2, default_scale);
+	}
+
+	/**
+	 * 两个实数相除,默认四舍五入到scale位
+	 *
+	 * @param v1
+	 * @param v2
+	 * @param scale
+	 * @return
+	 */
+	public static BigDecimal div(Object v1, Object v2, int scale) {
+		if (scale < 0) {
+			throw new IllegalArgumentException("四舍五入的位数不能为负数");
+		}
+		BigDecimal b1 = convert(v1);
+		BigDecimal b2 = convert(v2);
+		if (equal0(b2)) {
+			throw new IllegalArgumentException("除数不能为0");
+		}
+		return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP);
+	}
+
+	public static String formatDouble(double s) {
+		DecimalFormat fmt = new DecimalFormat("0.00");
+		return fmt.format(s);
+	}
+
+	public static String[] intersect(String[] arr1, String[] arr2){
+		List<String> l = new LinkedList<String>();
+		Set<String> common = new HashSet<String>();
+		for(String str:arr1){
+			if(!l.contains(str)){
+				l.add(str);
+			}
+		}
+		for(String str:arr2){
+			if(l.contains(str)){
+				common.add(str);
+			}
+		}
+		String[] result={};
+		return common.toArray(result);
+	}
+
+
+	public static synchronized String getUniqueString() {
+		if (generateCount > 99999) {generateCount = 0;}
+		String uniqueNumber = Long.toString(System.currentTimeMillis())
+				+ Integer.toString(generateCount);
+		generateCount++;
+		return uniqueNumber;
+	}
+
+	/**
+	 *
+	 * 构造函数
+	 */
+	private MathUtil() {
+
+	}
+
+	/**
+	 * 类型转换函数
+	 *
+	 * @param o
+	 * @return
+	 */
+	public static BigDecimal convert(Object o) {
+		if (o == null) {
+			return BigDecimal.ZERO;
+		} else if (o instanceof BigDecimal) {
+			return (BigDecimal) o;
+		}
+		String str = o.toString();
+		if (StringUtils.isNotBlank(str)) {
+			return new BigDecimal(str);
+		} else {
+			return BigDecimal.ZERO;
+		}
+	}
+
+	/**
+	 * 两个实数相加
+	 *
+	 * @param v1
+	 * @param v2
+	 * @return
+	 */
+	public static BigDecimal add(Object v1, Object v2) {
+		BigDecimal b1 = convert(v1);
+		BigDecimal b2 = convert(v2);
+		return b1.add(b2);
+
+	}
+
+	/**
+	 * 两个实数相减
+	 *
+	 * @param v1
+	 * @param v2
+	 * @return
+	 */
+	public static BigDecimal sub(Object v1, Object v2) {
+		BigDecimal b1 = convert(v1);
+		BigDecimal b2 = convert(v2);
+		return b1.subtract(b2);
+
+	}
+
+	/**
+	 * 两个实数相乘
+	 *
+	 * @param v1
+	 * @param v2
+	 * @return
+	 */
+	public static BigDecimal mul(Object v1, Object v2) {
+		BigDecimal b1 = convert(v1);
+		BigDecimal b2 = convert(v2);
+		return b1.multiply(b2);
+
+	}
+
+	/**
+	 * 相个实数相乘并四舍五入到Sacle位
+	 *
+	 * @param v1
+	 * @param v2
+	 * @param scale
+	 * @return
+	 */
+	public static BigDecimal mul(Object v1, Object v2, int scale) {
+		if (scale < 0) {
+			throw new IllegalArgumentException("四舍五入的位数不能为负数");
+		}
+		BigDecimal b1 = convert(v1);
+		BigDecimal b2 = convert(v2);
+		return b1.multiply(b2).setScale(scale, BigDecimal.ROUND_HALF_UP);
+
+	}
+
+	/**
+	 * 两个实数比较
+	 *
+	 * @param v1
+	 * @param v2
+	 * @return
+	 */
+	public static int compare(Object v1, Object v2) {
+		BigDecimal b1 = convert(v1);
+		BigDecimal b2 = convert(v2);
+		return b1.compareTo(b2);
+	}
+
+	public static boolean equal0(Object v1) {
+		BigDecimal b1 = convert(v1);
+		return b1.compareTo(BigDecimal.ZERO) == 0;
+	}
+
+	public static boolean notEqual0(Object v1) {
+		BigDecimal b1 = convert(v1);
+		return b1.compareTo(BigDecimal.ZERO) != 0;
+	}
+
+	/**
+	 * 两个整数比较
+	 *
+	 * @param v1
+	 * @param v2
+	 * @return
+	 */
+	public static int compareInt(Integer v1, Integer v2) {
+
+		if (v1 == null) {
+			v1 = new Integer(0);
+		}
+		if (v2 == null) {
+			v2 = new Integer(0);
+		}
+		return v1.compareTo(v2);
+	}
+
+	/**
+	 * 判断两个整数是否相等
+	 *
+	 * @param v1
+	 * @param v2
+	 * @return
+	 */
+	public static boolean equal(Integer v1, Integer v2) {
+
+		int result = compareInt(v1, v2);
+		return result == 0;
+	}
+
+	/**
+	 * 判断两个整数不等
+	 *
+	 * @param v1
+	 * @param v2
+	 * @return
+	 */
+	public static boolean notEqual(Integer v1, Integer v2) {
+		int result = compareInt(v1, v2);
+		return result != 0;
+	}
+
+	/**
+	 * 实数的四舍五入函数
+	 *
+	 * @param v
+	 * @param scale
+	 * @return
+	 */
+	public static BigDecimal round(Object v, int scale) {
+		if (scale < 0) {
+			throw new IllegalArgumentException("四舍五入的位数不能为负数");
+		}
+		BigDecimal b = convert(v);
+		return b.setScale(scale, BigDecimal.ROUND_HALF_UP);
+	}
+
+	/**
+	 * 将字符串转换成整型
+	 *
+	 * @param value
+	 * @param defaultNum
+	 * @return
+	 */
+	public static int parsetInt(String value, int defaultNum) {
+		if (value != null && !value.equals("")) {
+			int num = defaultNum;
+			try {
+				num = Integer.parseInt(value);
+			} catch (Exception ignored) {
+			}
+			return num;
+		} else {
+			return defaultNum;
+		}
+	}
+
+	/**
+	 * 将string转换为double
+	 *
+	 * @param value
+	 * @param defaultNum
+	 * @return
+	 */
+	public static double parseDouble(String value, double defaultNum) {
+		if (StringUtils.isBlank(value)) {
+			return defaultNum;
+		}
+
+		value = value.replaceAll(",", "");
+		value = value.replaceAll(" ", "");
+		value = value.replaceAll("¥", "");
+
+		double num = defaultNum;
+		try {
+			num = Double.parseDouble(value);
+		} catch (Exception ignored) {
+		}
+		return num;
+	}
+
+	/**
+	 * 将string 转换为double
+	 *
+	 * @param value
+	 * @return
+	 */
+	public static double parseDouble(String value) {
+		return parseDouble(value, 0);
+	}
+
+	public static int isNullInteger(Integer v) {
+		if (v == null) {
+			return 0;
+		} else {
+			return v.intValue();
+		}
+	}
+
+	//
+	private static double EARTH_RADIUS = 6378.137;
+
+	private static double rad(double d) {
+
+		return d * Math.PI / 180.0;
+
+	}
+
+	public static double getDistance(double lat1, double lng1, double lat2,
+
+	double lng2) {
+
+		double radLat1 = rad(lat1);
+
+		double radLat2 = rad(lat2);
+
+		double a = radLat1 - radLat2;
+
+		double b = rad(lng1) - rad(lng2);
+
+		double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
+
+		+ Math.cos(radLat1) * Math.cos(radLat2)
+
+		* Math.pow(Math.sin(b / 2), 2)));
+
+		s = s * EARTH_RADIUS;
+
+		s = Math.round(s * 10000) / 10000;
+
+		return s;
+
+	}
+
+	public static void main(String[] args){
+		double lat1=118.105736;
+		double lng1=24.491558;
+		double lat2=118.110749;
+		double lng2=24.492824;
+		double t=getDistance(lat1,lng1,lat2,lng2);
+		System.out.println(t);
+	}
+
+}

+ 1 - 1
src/main/java/caimei/utils/Md5Util.java → src/main/java/com/caimei/utils/Md5Util.java

@@ -1,4 +1,4 @@
-package caimei.utils;
+package com.caimei.utils;
 
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;

+ 1 - 1
src/main/java/caimei/utils/OSSUtils.java → src/main/java/com/caimei/utils/OSSUtils.java

@@ -1,4 +1,4 @@
-package caimei.utils;
+package com.caimei.utils;
 
 import com.aliyun.oss.OSS;
 import com.aliyun.oss.OSSClientBuilder;

+ 83 - 0
src/main/java/com/caimei/utils/OrderNoUtils.java

@@ -0,0 +1,83 @@
+package com.caimei.utils;
+
+
+import org.apache.commons.lang.ArrayUtils;
+
+import java.util.Random;
+
+/**
+ * 订单编号
+ *
+ * @author : Charles
+ * @date : 2020/3/19
+ */
+public class OrderNoUtils {
+    /**
+     * 订单模块生成新订单号
+     *
+     * @param platform
+     * @return
+     */
+    public static String getOrderNo(String platform) {
+        Random rand = new Random();
+        String code = "";
+        for (int j = 0; j < 5; j++) {
+            code += rand.nextInt(10) + "";
+        }
+        return platform + System.currentTimeMillis() / 1000 + code;
+    }
+
+
+    /***
+     * 子订单编号生成
+     * @param orderNo
+     * @param num
+     * @return
+     */
+    public static String getShopOrderNo(String orderNo, Integer num) {
+        if (num < 10) {
+            return orderNo + "0" + num;
+        } else {
+            return orderNo + num;
+        }
+    }
+
+    /**
+     * 根据订单列表类型获取订单状态
+     *
+     * @param listType
+     * @return status
+     */
+    public static int[] getStatusByListType(Integer listType) {
+        // listType:列表类型(1:待确认,2:待支付,3:待发货,4:已发货,5:退货退款)
+        switch (listType) {
+            case 1:
+                // status待确认(0)
+                return new int[]{0};
+            case 2:
+                // status待支付(21,22,23,11,12,13)
+                return new int[]{21, 22, 23, 11, 12, 13};
+            case 3:
+                // status待发货(11,12,21,22,31,32),
+                return new int[]{11, 12, 21, 22, 31, 32};
+            case 4:
+                // status已发货(12,13,22,23,32,33),
+                return new int[]{12, 13, 22, 23, 32, 33};
+            case 5:
+                // status退货退款(1,2)
+                return new int[]{1, 2, 7};
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * 是否包含订单充值商品或定金商品
+     * @param productId 商品id
+     * @return
+     */
+    public static boolean getRechargeProduct(Integer productId){
+        int[] products = {6060, 6061, 6062, 6063, 6064, 6065, 6066, 6067, 6068, 6069};
+        return ArrayUtils.contains(products, productId);
+    }
+}

+ 128 - 0
src/main/java/com/caimei/utils/ProductUtils.java

@@ -0,0 +1,128 @@
+package com.caimei.utils;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2020/3/25
+ */
+public class ProductUtils {
+	public static String getImageURL(String dirName, String src, String domain) {
+		return getImageURL(dirName, src, 0,domain);
+	}
+	/***
+	 * 获取图片地址
+	 *
+	 * @param src
+	 *            保存在数据库中的图片文件名
+	 * @param type
+	 *            图片的前缀 (如 type = 200 那么则获取的图片是 200_XXX的图片)
+	 * @param dirName
+	 *            图片保存的文件夹名 如 (league)
+	 * @param domain
+	 * 			   加上域名拼成完整路径
+	 * @return
+	 */
+	public static String getImageURL(String dirName, String src, int type, String domain) {
+
+
+		//正式环境 域名 http --- https处理
+		if (domain != null && !"".equals(domain) && domain.startsWith("http:") && domain.toLowerCase().lastIndexOf("test")== -1 && domain.toLowerCase().lastIndexOf("localhost")== -1) {
+			domain = domain.replace("http:", "https:");
+		}
+
+		//正式环境 图片地址 http --- https处理
+		if(src != null && src.startsWith("https:")){
+			//非正式环境 使用http
+			if (domain !=null && !"".equals(domain) && domain.toLowerCase().lastIndexOf("test")>-1 || domain.toLowerCase().lastIndexOf("localhost")>-1){
+				src = src.replace("https:","http:");
+			}
+			return src;
+		}
+
+		//正式环境 图片地址  http --- https处理
+		if(src != null && src.startsWith("http:")){
+			//非正式环境 使用http
+			if (domain !=null && !"".equals(domain) && domain.toLowerCase().lastIndexOf("test")==-1 && domain.toLowerCase().lastIndexOf("localhost")==-1){
+				src = src.replace("http:","https:");
+			}
+			return src;
+		}
+		type = 0 ;
+		dirName = dirName.trim();
+		if (dirName == null) {dirName = "";}
+		if(src == null || src.equalsIgnoreCase("null")) {src = "";}
+		if (src.indexOf(",") > 0) {
+			String tmp = src;
+			src = tmp.substring(0, tmp.indexOf(","));
+		}
+		String image = "/img/default/none.jpg";
+		if (dirName.equals("user")) {
+			image = "/img/default/HeaderImg.png";
+		} else if (dirName.equals("club")) {
+			image = "/img/default/default_club.jpg";
+		} else if (dirName.equals("shopLogo")) {
+			image = "/img/default/suppliver.jpg";
+		}else if (dirName.equals("caiMeiImage")) {
+			image = "/img/default/caiMeiImage.jpg";
+		}else {
+			image = "/img/default/none.jpg";
+		}
+		if (src != null && !src.equals("")) {
+			if (type != 0 || dirName.equals("product")) {
+				src = src.replace("\\", "/");
+				String srcActual = src;
+				String subDirName = "";
+				int index = src.lastIndexOf("/");
+
+				if (index != -1) {
+					subDirName = src.substring(0, index + 1);
+					srcActual = src.substring(index + 1);
+				}
+				boolean b = src.startsWith("/uploadFile");
+				if(b){
+					image = src;
+				}else{
+					image = "/uploadFile/" + dirName + "/" + subDirName
+							+ (type == 0 ? "" : type + "_") + srcActual;
+				}
+			} else {
+				boolean b = src.startsWith("/uploadFile");
+				if(b){
+					image = src;
+				}else{
+					image = "/uploadFile/" + dirName + "/" + src;
+				}
+			}
+		}else {
+			if(StringUtils.isEmpty(image)) {
+				image = "/img/default/none.jpg";
+			}
+		}
+		return domain + image;
+	}
+
+	public static String getProductImageURL(String image, int type, String domain) {
+		if (image == null) {
+			return getImageURL("product", "", type, domain);
+		}
+		return getImageURL("product", image, type, domain);
+	}
+
+	public static String getPriceGrade(Double price){
+        if (price <= 2.5 * 10000L) {
+        	return "1";
+        } else if (price <= 10 * 10000) {
+            return "2";
+        } else if (price <= 25 * 10000) {
+            return "3";
+        } else if (price <= 50 * 10000) {
+            return "4";
+        } else {
+            return "5";
+        }
+	}
+
+}

+ 107 - 0
src/main/java/com/caimei/utils/RSAUtil.java

@@ -0,0 +1,107 @@
+package com.caimei.utils;
+
+
+
+import com.caimei.model.enumerate.KeyFormat;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class RSAUtil {
+
+    public static Map<String, String> createKeys() throws NoSuchAlgorithmException {
+        //为RSA算法创建一个KeyPairGenerator对象
+        KeyPair keyPair = KeyGenerator.generateKeyPair();
+        KeyPair asnKeyPair = keyPair.toASNKeyPair();
+        //得到公钥
+        String publicKey = asnKeyPair.getPublicKey();
+        String privateKey = asnKeyPair.getPrivateKey();
+        Map<String, String> keyPairMap = new HashMap<String, String>();
+        keyPairMap.put("publicKey", publicKey);
+        keyPairMap.put("privateKey", privateKey);
+
+        return keyPairMap;
+    }
+
+    /**
+     * 公钥加密
+     *
+     * @param data
+     * @param publicKey
+     * @return
+     */
+    public static String publicEncrypt(String data, String publicKey) {
+        try {
+            KeyWorker publicWorker = new KeyWorker(publicKey, KeyFormat.ASN);
+            return publicWorker.encrypt(data);
+        } catch (Exception e) {
+            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
+        }
+    }
+
+    /**
+     * 私钥解密
+     *
+     * @param data
+     * @param privateKey
+     * @return
+     */
+
+    public static String privateDecrypt(String data, String privateKey) {
+        try {
+            KeyWorker privateWorker = new KeyWorker(privateKey, KeyFormat.ASN);
+            return privateWorker.decrypt(data);
+        } catch (Exception e) {
+            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
+        }
+    }
+
+    /**
+     * 私钥加密
+     *
+     * @param data
+     * @param privateKey
+     * @return
+     */
+
+    public static String privateEncrypt(String data, String privateKey) {
+        try {
+            KeyWorker privateWorker = new KeyWorker(privateKey, KeyFormat.ASN);
+            return privateWorker.encrypt(data);
+        } catch (Exception e) {
+            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
+        }
+    }
+
+    /**
+     * 公钥解密
+     *
+     * @param data
+     * @param publicKey
+     * @return
+     */
+
+    public static String publicDecrypt(String data, String publicKey) {
+        try {
+            KeyWorker publicWorker = new KeyWorker(publicKey, KeyFormat.ASN);
+            return publicWorker.decrypt(data);
+        } catch (Exception e) {
+            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
+        }
+    }
+
+    public static void main(String[] args) throws NoSuchAlgorithmException {
+        Map<String, String> keys = createKeys();
+        String publicKey = keys.get("publicKey");
+        String privateKey = keys.get("privateKey");
+        System.out.println("private:" + privateKey);
+        System.out.println("public:" + publicKey);
+        String conent = "sdsfalfasdl2对方是否";
+        String en = publicEncrypt(conent, publicKey);
+        System.out.println("公钥加密:" + en);
+        String de = privateDecrypt(en, privateKey);
+        System.out.println("私钥解密:" + de);
+    }
+
+}

+ 174 - 0
src/main/java/com/caimei/utils/XmlKeyBuilder.java

@@ -0,0 +1,174 @@
+package com.caimei.utils;
+
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import sun.misc.BASE64Decoder;
+import sun.misc.BASE64Encoder;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+/*
+ Jeffrey Walton
+ http://www.codeproject.com/Articles/25487/Cryptographic-Interoperability-Keys
+ */
+public class XmlKeyBuilder {
+    public static String publicKeyToXML(PublicKey key) {
+        if (!RSAPublicKey.class.isInstance(key)) {
+            return null;
+        }
+        RSAPublicKey pubKey = (RSAPublicKey) key;
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("<RSAKeyValue>");
+        sb.append("<Modulus>")
+                .append(new BASE64Encoder().encode(TrimLeadingZero(pubKey.getModulus()
+                        .toByteArray()))).append("</Modulus>");
+        sb.append("<Exponent>")
+                .append(new BASE64Encoder().encode(TrimLeadingZero(pubKey.getPublicExponent()
+                        .toByteArray()))).append("</Exponent>");
+        sb.append("</RSAKeyValue>");
+        return sb.toString();
+    }
+
+    public static String privateKeyToXML(PrivateKey key) {
+        if (!RSAPrivateCrtKey.class.isInstance(key)) {
+            return null;
+        }
+        RSAPrivateCrtKey priKey = (RSAPrivateCrtKey) key;
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("<RSAKeyValue>");
+        sb.append("<Modulus>")
+                .append(new BASE64Encoder().encode(TrimLeadingZero(priKey.getModulus()
+                        .toByteArray()))).append("</Modulus>");
+        sb.append("<Exponent>")
+                .append(new BASE64Encoder().encode(TrimLeadingZero(priKey.getPublicExponent()
+                        .toByteArray()))).append("</Exponent>");
+        sb.append("<P>")
+                .append(new BASE64Encoder().encode(TrimLeadingZero(priKey.getPrimeP()
+                        .toByteArray()))).append("</P>");
+        sb.append("<Q>")
+                .append(new BASE64Encoder().encode(TrimLeadingZero(priKey.getPrimeQ()
+                        .toByteArray()))).append("</Q>");
+        sb.append("<DP>")
+                .append(new BASE64Encoder().encode(TrimLeadingZero(priKey.getPrimeExponentP()
+                        .toByteArray()))).append("</DP>");
+        sb.append("<DQ>")
+                .append(new BASE64Encoder().encode(TrimLeadingZero(priKey.getPrimeExponentQ()
+                        .toByteArray()))).append("</DQ>");
+        sb.append("<InverseQ>")
+                .append(new BASE64Encoder().encode(TrimLeadingZero(priKey.getCrtCoefficient()
+                        .toByteArray()))).append("</InverseQ>");
+        sb.append("<D>")
+                .append(new BASE64Encoder().encode(TrimLeadingZero(priKey.getPrivateExponent()
+                        .toByteArray()))).append("</D>");
+        sb.append("</RSAKeyValue>");
+        return sb.toString();
+    }
+
+    public static PublicKey xmlToPublicKey(String key)
+            throws ParserConfigurationException, SAXException, IOException {
+        key = key.replaceAll("\r", "").replaceAll("\n", "");
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        Document doc = builder.parse(new InputSource(new ByteArrayInputStream(
+                key.getBytes("utf-8"))));
+        String n = doc.getDocumentElement().getElementsByTagName("Modulus")
+                .item(0).getNodeValue();
+        String e = doc.getDocumentElement().getElementsByTagName("Exponent")
+                .item(0).getNodeValue();
+        BigInteger modulus = new BigInteger(1,
+                new BASE64Decoder().decodeBuffer(n));
+        BigInteger publicExponent = new BigInteger(1,
+                new BASE64Decoder().decodeBuffer(e));
+
+        RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus,
+                publicExponent);
+
+        KeyFactory keyf;
+        try {
+            keyf = KeyFactory.getInstance("RSA");
+            return keyf.generatePublic(rsaPubKey);
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    public static PrivateKey xmlToPrivateKey(String key) throws IOException,
+            SAXException, ParserConfigurationException {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        Document doc = builder.parse(new InputSource(new ByteArrayInputStream(
+                key.getBytes("utf-8"))));
+        String n = doc.getDocumentElement().getElementsByTagName("Modulus")
+                .item(0).getNodeValue();
+        String e = doc.getDocumentElement().getElementsByTagName("Exponent")
+                .item(0).getNodeValue();
+        String d = doc.getDocumentElement().getElementsByTagName("D").item(0)
+                .getNodeValue();
+        String p = doc.getDocumentElement().getElementsByTagName("P").item(0)
+                .getNodeValue();
+        String q = doc.getDocumentElement().getElementsByTagName("Q").item(0)
+                .getNodeValue();
+        String dp = doc.getDocumentElement().getElementsByTagName("DP").item(0)
+                .getNodeValue();
+        String dq = doc.getDocumentElement().getElementsByTagName("DQ").item(0)
+                .getNodeValue();
+        String inverseQ = doc.getDocumentElement()
+                .getElementsByTagName("InverseQ").item(0).getNodeValue();
+
+        key = key.replaceAll("\r", "").replaceAll("\n", "");
+        BigInteger modulus = new BigInteger(1,
+                new BASE64Decoder().decodeBuffer(n));
+        BigInteger publicExponent = new BigInteger(1,
+                new BASE64Decoder().decodeBuffer(e));
+        BigInteger privateExponent = new BigInteger(1,
+                new BASE64Decoder().decodeBuffer(d));
+        BigInteger primeP = new BigInteger(1,
+                new BASE64Decoder().decodeBuffer(p));
+        BigInteger primeQ = new BigInteger(1,
+                new BASE64Decoder().decodeBuffer(q));
+        BigInteger primeExponentP = new BigInteger(1,
+                new BASE64Decoder().decodeBuffer(dp));
+        BigInteger primeExponentQ = new BigInteger(1,
+                new BASE64Decoder().decodeBuffer(dq));
+        BigInteger crtCoefficient = new BigInteger(1,
+                new BASE64Decoder().decodeBuffer(inverseQ));
+
+        RSAPrivateCrtKeySpec rsaPriKey = new RSAPrivateCrtKeySpec(modulus,
+                publicExponent, privateExponent, primeP, primeQ,
+                primeExponentP, primeExponentQ, crtCoefficient);
+
+        KeyFactory keyf;
+        try {
+            keyf = KeyFactory.getInstance("RSA");
+            return keyf.generatePrivate(rsaPriKey);
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    static byte[] TrimLeadingZero(byte[] values) {
+        if ((0x00 == values[0]) && (values.length > 1)) {
+            byte[] r = null;
+            r = new byte[values.length - 1];
+            System.arraycopy(values, 1, r, 0, r.length);
+            return r;
+        }
+
+        return values;
+    }
+}

+ 2 - 2
src/main/resources/application.yml

@@ -1,9 +1,9 @@
 server:
-  port: 8012
+  port: 8013
 spring:
   application:
     # 指定服务名
-    name: caimei-zplm-admin
+    name: caimei-purchase-api
   profiles:
     active: @activatedProperties@
 

+ 3 - 0
src/main/resources/backup.sql

@@ -46,3 +46,6 @@ CREATE TABLE `api_organize_product_ladder_price` (
     DEFAULT CHARACTER SET = utf8
     COLLATE = utf8_bin
     COMMENT = '对接组织商品阶梯价格表';
+
+ALTER TABLE `cm_order`
+    ADD COLUMN `apiOrganizeOrderId` VARCHAR(32) NULL COMMENT '对接组织的订单Id,由组织自行生成' AFTER `orderNo`;

+ 3 - 3
src/main/resources/config/dev/application-dev.yml

@@ -18,9 +18,9 @@ spring:
   #数据源连接--end
 
   redis:
-    host: 119.29.0.46
-    port: 6380
-    password: 6#xsI%b4o@5c3RoE
+    host: 192.168.2.100
+    port: 6379
+#    password: 6#xsI%b4o@5c3RoE
     #Redis数据库索引(默认为0)
     database: 0
     #连接池最大连接数(使用负值表示没有限制)

+ 10 - 0
src/main/resources/mapper/OrganizeMapper.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.caimei.mapper.OrganizeMapper">
+
+    <select id="getOrganizeByCmAccount" resultType="com.caimei.model.po.CmApiOrganizePo">
+        select id as organizeId, userId, cmAccount, privateKey, publicKey, notifyUrl
+        from cm_api_organize
+        where cmAccount = #{cmAccount};
+    </select>
+</mapper>

+ 154 - 0
src/main/resources/mapper/ProductMapper.xml

@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.caimei.mapper.ProductMapper">
+
+    <select id="getProductByProductId" resultType="com.caimei.model.po.CmApiOrganizeProductPo">
+        SELECT cop.id,
+               cop.organizeId,
+               cop.productId,
+               cop.ladderPriceFlag,
+               cop.price,
+               cop.includedTax,
+               cop.invoiceType,
+               cop.minBuyNumber,
+               cop.costType,
+               cop.clubTaxPoint,
+               cop.shopTaxPoint,
+               cop.costPrice,
+               cop.costProportional,
+               p.shopID AS shopId,
+               p.unit,
+               p.normalPrice,
+               p.name,
+               p.mainImage,
+               s.name   AS shopName
+        FROM cm_api_organize_product cop
+                 LEFT JOIN product p ON cop.productId = p.productID
+                 LEFT JOIN shop s ON p.shopID = s.shopID
+        WHERE cop.id = #{productId}
+    </select>
+    <select id="getLadderPriceByProductId" resultType="com.caimei.model.vo.LadderPriceVo">
+        SELECT id,
+               productId,
+               ladderNum,
+               buyNum,
+               buyPrice
+        FROM api_organize_product_ladder_price
+        WHERE productId = #{productId}
+        ORDER BY ladderNum ASC
+    </select>
+    <select id="findLadderPriceByProductId" resultType="com.caimei.model.vo.LadderPriceVo">
+        SELECT id,
+               productId,
+               ladderNum,
+               buyNum,
+               buyPrice
+        FROM api_organize_product_ladder_price
+        WHERE productId = #{productId}
+        ORDER BY ladderNum ASC
+    </select>
+    <select id="findPostFeeProduct" resultType="com.caimei.model.po.ProductPo">
+        SELECT p.productID,
+               p.ladderPriceFlag,
+               p.price1,
+               p.includedTax,
+               p.invoiceType,
+               p.minBuyNumber,
+               p.taxPoint,
+               p.supplierTaxPoint,
+               p.costPrice,
+               p.costProportional,
+               p.shopID,
+               p.unit,
+               p.normalPrice,
+               p.name,
+               p.mainImage,
+               p.productCode,
+               s.name AS shopName
+        FROM product p
+                 LEFT JOIN shop s ON p.shopID = s.shopID
+        WHERE p.productID = 999
+    </select>
+    <select id="getProductList" resultType="com.caimei.model.vo.ProductVo">
+        select
+        cop.id as productId,
+        p.name as productName,
+        b.name as brandName,
+        p.mainImage,
+        p.unit,
+        s.name as shopName,
+        cop.price,
+        cop.minBuyNumber,
+        cop.ladderPriceFlag,
+        cop.includedTax,
+        cop.invoiceType,
+        cop.clubTaxPoint
+        from cm_api_organize_product cop
+        left join product p on cop.productId = p.productID
+        left join cm_brand b on p.brandID = b.id
+        left join shop s on p.shopID = s.shopID
+        where cop.organizeId = #{organizeId} and cop.delFlag = 0 and cop.status = 1
+        <if test="productName != null and productName != ''">
+            and p.name like concat('%',#{productName},'%')
+        </if>
+        order by cop.addTime desc
+    </select>
+    <select id="findProductByProductId" resultType="com.caimei.model.vo.ProductVo">
+        select cop.id           as productId,
+               cop.productId    as originalProductId,
+               cop.price,
+               cop.minBuyNumber,
+               cop.ladderPriceFlag,
+               cop.includedTax,
+               cop.invoiceType,
+               cop.clubTaxPoint,
+               cop.status,
+               b.name           as brandName,
+               p.name           as productName,
+               s.name           as shopName,
+               p.mainImage,
+               p.unit,
+               p.tags,
+               p.brandID        as brandId,
+               p.productRemarks as productRemark,
+               p.productCode,
+               p.stock
+        from cm_api_organize_product cop
+                 left join product p on cop.productId = p.productID
+                 left join cm_brand b on p.brandID = b.id
+                 left join shop s on p.shopID = s.shopID
+        where cop.delFlag = 0
+          and cop.id = #{productId}
+          and cop.organizeId = #{organizeId}
+    </select>
+    <select id="findProductImagesByOriginalId" resultType="com.caimei.model.po.ProductImagePo">
+        select
+            productImageID as productImageId, productID as productId, shopID as shopId, addTime, image, mainFlag, sortIndex
+        from productimage
+        where productID = #{productId}
+        ORDER BY mainFlag DESC
+    </select>
+    <select id="findProductDetailByOriginalId" resultType="com.caimei.model.po.ProductDetailInfoPo">
+        select
+            productDetailInfoID as productDetailInfoId, productID as productId, propValueAlias, propValueImages, detailInfo, detailInfoTxt,
+            seoTitle, seoKeyword, seoDes, serviceInfo, orderInfo
+        from productdetailinfo
+        where productID = #{productId,jdbcType=BIGINT}
+    </select>
+    <select id="getOrderProduct" resultType="com.caimei.model.vo.OrderProductVo">
+        SELECT
+            cop.*,
+            p.mainImage AS productImage,
+            p.productCategory as productCategory,
+            caop.id as apiOrganizeProductId
+        FROM
+            cm_order_product cop
+                LEFT JOIN product p ON cop.productID = p.productID
+                left join cm_api_organize_product caop on p.productID = caop.productId
+        WHERE
+            orderID = #{orderID}
+    </select>
+
+</mapper>

+ 130 - 3
src/test/java/caimei/PurchaseApplicationTests.java

@@ -1,7 +1,12 @@
-package com.caimei;
-
+package caimei;
 
+import com.alibaba.fastjson.JSONObject;
 import com.aliyun.oss.internal.OSSUtils;
+import com.caimei.model.ResponseJson;
+import com.caimei.utils.Base64;
+import com.caimei.utils.KeyGenerator;
+import com.caimei.utils.KeyPair;
+import com.caimei.utils.KeyUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -15,15 +20,137 @@ import java.awt.*;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.UUID;
 
 @SpringBootTest
 public class PurchaseApplicationTests {
 
+    //private String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDawyiPFWo4tSS1YX/mXTIGWghehyYfec2JeQFJONfLTOcyJ11RP+19E3QSn6JiclYbRM+Rzt/gvFOnVAyvZ6VUFkIZlMr9ykqB74crQs6pw4AY0lREscV8yk5QYEGPCv3I97A8Pm44ThWGuXQ1cjmxBk+zS4xR2Yu+jPZb65HsNwIDAQAB";
+    private String privateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANrDKI8Vaji1JLVhf+ZdMgZaCF6HJh95zYl5AUk418tM5zInXVE/7X0TdBKfomJyVhtEz5HO3+C8U6dUDK9npVQWQhmUyv3KSoHvhytCzqnDgBjSVESxxXzKTlBgQY8K/cj3sDw+bjhOFYa5dDVyObEGT7NLjFHZi76M9lvrkew3AgMBAAECgYBFSyISyI6/7aj2By8zMfwBhQ03nAmYWMWhMQIWRnocPHzTJyLo9J3uS3Yt3ADcvCjINHCnV+cUUbMRwo7OFL+KH+NDeLBmv0b+oMoVeOhgJZWkpt+O4bA90+NrA4P3sPqPbJUG1fqtm+Ll8wTASrLxrwyiRn2VRCfwMRTqaTc9sQJBAPqvhe+Ler0dx82kXxr+gwOdRJLqYCqverP66obKRamOG0wF9Hj04fTgz0iwiQK/Jpvu4jfPg6fWyGvGq6lNFdkCQQDfZmMCOHowT9AS21VZYJVE+cBZjg2aP5XV1rXPnOi18cBaDwo8EIIO9gXPtk1GtMeuVf9esXNfSI8SI9GtTXiPAkEAl7UTXAVP8RUNrqCTwbVWuiA5uKNIMWzi1/q4ZXwRrmvGjzpnWa/w8o3+Q6I6OERP7DwkANx/c1ojDj478ogo+QJAfK3H1BVxHEVu+xcuKxOcO0Kn91MwhEW4ef+6uIP53JFvqNN8AsmzzGXCGIrF1hBO4R1dyJuAqEz2jEkxXGdAQQJBAKKFeQ6eiHzwWeiiuMG0Hge4gTPra4v4lHtxcFfqv3tlQ+7LVnw4+4YBMqXRoW+CbwCYhrvoaOqSYTq0xvkctGo=";
+    private String cmAccount = "AAD38EE44AC49124B18C089717ED10B0";
+
+
+    @Test
+    public void productList() throws Exception {
+        JSONObject json = new JSONObject();
+        json.put("pageNum", 1);
+        json.put("pageSize", 10);
+        json.put("productName", "精华油");
+        // 私钥签名
+        String sign = KeyUtils.buildSign(json, privateKey);
+        json.put("sign", sign);
+        // 私钥加密
+        String data = KeyUtils.buildDataPrivate(json, privateKey);
+        System.out.println(data);
+        // 发送请求
+        JSONObject result = KeyUtils.httpPost("http://localhost:8013/product/list", cmAccount, data);
+        String code = result.getString("code");
+    }
+
+    @Test
+    public void productDetail() throws Exception {
+        JSONObject json = new JSONObject();
+        json.put("productId", "0002");
+        // 私钥签名
+        String sign = KeyUtils.buildSign(json, privateKey);
+        json.put("sign", sign);
+        // 私钥加密
+        String data = KeyUtils.buildDataPrivate(json, privateKey);
+        System.out.println(data);
+        // 发送请求
+        JSONObject result = KeyUtils.httpPost("http://localhost:8013/product/detail", cmAccount, data);
+        String code = result.getString("code");
+    }
 
     @Test
-    public void JWTToken(){
+    public void orderSubmit() throws Exception {
+        JSONObject json = new JSONObject();
+        json.put("orderId", "cm8870");
+        JSONObject addressInfoMap =  new JSONObject();
+        addressInfoMap.put("provinceName", "广东省");
+        addressInfoMap.put("cityName", "深圳市");
+        addressInfoMap.put("townName", "福田区");
+        addressInfoMap.put("addressDetail", "会展中心");
+        addressInfoMap.put("receiveMan", "王老五");
+        addressInfoMap.put("mobile", "15828899221");
+        json.put("addressInfo", addressInfoMap);
+        JSONObject productInfoMap =  new JSONObject();
+        productInfoMap.put("0001", 2);
+        productInfoMap.put("0002", 3);
+        productInfoMap.put("0003", 4);
+        json.put("productInfo", productInfoMap);
+        JSONObject payInfoMap = new JSONObject();
+        payInfoMap.put("orderShouldPayFee", 3253.75f);
+        payInfoMap.put("freight", 0);
+        payInfoMap.put("freePostFlag", -1);
+        json.put("payInfo", payInfoMap);
+        JSONObject orderInvoiceMap = new JSONObject();
+        orderInvoiceMap.put("type", 2);
+        orderInvoiceMap.put("invoiceTitle", "单位名称");
+        orderInvoiceMap.put("corporationTaxNum", "NSRSBM97897");
+        orderInvoiceMap.put("registeredAddress", "注册地址");
+        orderInvoiceMap.put("registeredPhone", "15814011616");
+        orderInvoiceMap.put("openBank", "开户银行");
+        orderInvoiceMap.put("bankAccountNo", "987987465465464");
+        json.put("orderInvoice", orderInvoiceMap);
+//        String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDawyiPFWo4tSS1YX/mXTIGWghehyYfec2JeQFJONfLTOcyJ11RP+19E3QSn6JiclYbRM+Rzt/gvFOnVAyvZ6VUFkIZlMr9ykqB74crQs6pw4AY0lREscV8yk5QYEGPCv3I97A8Pm44ThWGuXQ1cjmxBk+zS4xR2Yu+jPZb65HsNwIDAQAB";
+        String privateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANrDKI8Vaji1JLVhf+ZdMgZaCF6HJh95zYl5AUk418tM5zInXVE/7X0TdBKfomJyVhtEz5HO3+C8U6dUDK9npVQWQhmUyv3KSoHvhytCzqnDgBjSVESxxXzKTlBgQY8K/cj3sDw+bjhOFYa5dDVyObEGT7NLjFHZi76M9lvrkew3AgMBAAECgYBFSyISyI6/7aj2By8zMfwBhQ03nAmYWMWhMQIWRnocPHzTJyLo9J3uS3Yt3ADcvCjINHCnV+cUUbMRwo7OFL+KH+NDeLBmv0b+oMoVeOhgJZWkpt+O4bA90+NrA4P3sPqPbJUG1fqtm+Ll8wTASrLxrwyiRn2VRCfwMRTqaTc9sQJBAPqvhe+Ler0dx82kXxr+gwOdRJLqYCqverP66obKRamOG0wF9Hj04fTgz0iwiQK/Jpvu4jfPg6fWyGvGq6lNFdkCQQDfZmMCOHowT9AS21VZYJVE+cBZjg2aP5XV1rXPnOi18cBaDwo8EIIO9gXPtk1GtMeuVf9esXNfSI8SI9GtTXiPAkEAl7UTXAVP8RUNrqCTwbVWuiA5uKNIMWzi1/q4ZXwRrmvGjzpnWa/w8o3+Q6I6OERP7DwkANx/c1ojDj478ogo+QJAfK3H1BVxHEVu+xcuKxOcO0Kn91MwhEW4ef+6uIP53JFvqNN8AsmzzGXCGIrF1hBO4R1dyJuAqEz2jEkxXGdAQQJBAKKFeQ6eiHzwWeiiuMG0Hge4gTPra4v4lHtxcFfqv3tlQ+7LVnw4+4YBMqXRoW+CbwCYhrvoaOqSYTq0xvkctGo=";
+        // 私钥签名
+        String sign = KeyUtils.buildSign(json, privateKey);
+        json.put("sign", sign);
+        // 私钥加密
+        String data = KeyUtils.buildDataPrivate(json, privateKey);
+        System.out.println(data);
+        // 发送请求
+//        JSONObject result = KeyUtils.httpPost("http://localhost:8013/order/submit", cmAccount, data);
+//        String code = result.getString("code");
     }
 
+    @Test
+    public void orderDetail() throws Exception {
+        JSONObject json = new JSONObject();
+        json.put("orderId", "cm8870");
+        // 私钥签名
+        String sign = KeyUtils.buildSign(json, privateKey);
+        json.put("sign", sign);
+        // 私钥加密
+        String data = KeyUtils.buildDataPrivate(json, privateKey);
+        System.out.println(data);
+        // 发送请求
+//        JSONObject result = KeyUtils.httpPost("http://localhost:8013/order/detail", cmAccount, data);
+//        String code = result.getString("code");
+    }
 
+
+    @Test
+    public void orderCancel() throws Exception {
+        JSONObject json = new JSONObject();
+        json.put("orderId", "cm8869");
+        // 私钥签名
+        String sign = KeyUtils.buildSign(json, privateKey);
+        json.put("sign", sign);
+        // 私钥加密
+        String data = KeyUtils.buildDataPrivate(json, privateKey);
+        System.out.println(data);
+        // 发送请求
+//        JSONObject result = KeyUtils.httpPost("http://localhost:8013/order/detail", cmAccount, data);
+//        String code = result.getString("code");
+    }
+
+
+
+
+    @Test
+    public void buildKey() throws NoSuchAlgorithmException {
+        KeyPair keyPair = KeyGenerator.generateKeyPair();
+        String publicKey = keyPair.getPublicKey();
+        String privateKey = keyPair.getPrivateKey();
+        System.out.println(publicKey);
+        System.out.println(privateKey);
+    }
 }