Browse Source

登录与识别收款短信

chao 3 years ago
parent
commit
820d68da62

+ 43 - 1
backup.sql

@@ -76,4 +76,46 @@ ALTER TABLE `caimei`.`cm_order_product`
     ADD COLUMN `svipPriceFlag` INT NULL DEFAULT 0 COMMENT '超级会员优惠价格标识:0不是,1是' AFTER `heUserId`,
     ADD COLUMN `svipPriceType` INT NULL DEFAULT NULL COMMENT '超级会员优惠价类型:1折扣价,2直接优惠价' AFTER `svipPriceFlag`,
     ADD COLUMN `svipDiscount` DECIMAL(20,2) NULL DEFAULT '0.00' COMMENT '超级会员折扣' AFTER `svipPriceFlag`,
-    ADD COLUMN `svipReduction` DECIMAL(20,2) NULL DEFAULT 0.00 COMMENT '超级会员优惠' AFTER `svipDiscount`;
+    ADD COLUMN `svipReduction` DECIMAL(20,2) NULL DEFAULT 0.00 COMMENT '超级会员优惠' AFTER `svipDiscount`;
+
+-- ===========================CRM收款工具重构================================
+-- 收款用户表
+DROP TABLE IF EXISTS `cm_receipt_user`;
+CREATE TABLE `cm_receipt_user` (
+  `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '收款用户ID',
+  `mobile` VARCHAR(11) NULL COMMENT '收款用户手机号',
+  `password` VARCHAR(255) NULL COMMENT '收款用户密码',
+  `openid` varchar(255) NULL COMMENT '收款用户微信openid',
+  `user_type` char(2) NULL COMMENT '收款用户类型:1协销人员,2客服,3财务,4超级管理员',
+  `name` VARCHAR(100) NOT NULL COMMENT '姓名',
+  `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
+  `update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
+  `del_flag` CHAR(1) NOT NULL DEFAULT '0' COMMENT '删除标记:0未删,其他删除',
+  PRIMARY KEY (`id`)
+) ENGINE=INNODB DEFAULT CHARSET=UTF8MB4 COMMENT='采美收款用户表';
+ -- 收款用户权限表
+DROP TABLE IF EXISTS `cm_receipt_user_permission`;
+CREATE TABLE `cm_receipt_user_permission` (
+  `id` BIGINT NOT NULL AUTO_INCREMENT,
+  `user_id` BIGINT DEFAULT NULL COMMENT '收款用户ID',
+  `permission` BIGINT DEFAULT NULL COMMENT '权限:1录入收款权限,2收款确认权限,3收款审核权限 4返佣管理权限 5供应商退款管理权限',
+  PRIMARY KEY (`id`)
+) ENGINE=INNODB DEFAULT CHARSET=UTF8MB4 COMMENT='采美收款用户权限表';
+ -- 收款类型表
+DROP TABLE IF EXISTS `cm_receipt_type`;
+CREATE TABLE `cm_receipt_type` (
+  `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '收款类型ID',
+  `type` VARCHAR(100) NOT NULL COMMENT '收款类型',
+  PRIMARY KEY (`id`)
+) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='采美收款类型表';
+-- 初始数据
+INSERT  INTO `cm_receipt_type`(`id`,`type`) VALUES (1,'建设银行-7297'),(2,'广发银行-0115'),(3,'中信银行-7172'),(4,'中信银行-0897'),(5,'中信银行-0897-财付通'),(6,'中信银行-0897-支付宝'),(7,'线上-支付宝'),(8,'线上-微信支付'),(9,'线上-快钱支付'),(10,'口头返佣'),(11,'广发银行-5461'),(12,'企业网银'),(13,'微信支付'),(14,'支付宝'),(15,'微信支付'),(16,'余额抵扣'),(18,'建设银行-1854'),(19,'建设银行-6256');
+
+
+
+
+
+
+
+
+

+ 42 - 0
src/main/java/com/caimei365/order/components/WeChatService.java

@@ -40,6 +40,10 @@ public class WeChatService {
     private String miniAppId;
     @Value("${wx.mini-app-secret}")
     private String miniAppSecret;
+    @Value("${wx.receipt-app-id}")
+    private String receiptAppId;
+    @Value("${wx.receipt-app-secret}")
+    private String receiptAppSecret;
     @Value("${wx.crm-app-id}")
     private String crmAppId;
     @Value("${wx.crm-app-secret}")
@@ -69,6 +73,38 @@ public class WeChatService {
         miniAppSecret = miniAppSecret;
     }
 
+    public String getReceiptAppId() {
+        return receiptAppId;
+    }
+
+    public void setReceiptAppId(String receiptAppId) {
+        this.receiptAppId = receiptAppId;
+    }
+
+    public String getReceiptAppSecret() {
+        return receiptAppSecret;
+    }
+
+    public void setReceiptAppSecret(String receiptAppSecret) {
+        this.receiptAppSecret = receiptAppSecret;
+    }
+
+    public String getHeHeAppId() {
+        return heHeAppId;
+    }
+
+    public void setHeHeAppId(String heHeAppId) {
+        this.heHeAppId = heHeAppId;
+    }
+
+    public String getHeHeAppSecret() {
+        return heHeAppSecret;
+    }
+
+    public void setHeHeAppSecret(String heHeAppSecret) {
+        this.heHeAppSecret = heHeAppSecret;
+    }
+
     public void setCrmAppId(String crmAppId) {
         crmAppId = crmAppId;
     }
@@ -173,6 +209,12 @@ public class WeChatService {
             log.info("采美小程序appId: ---" + miniAppId);
             // 小程序appSecret
             requestUrlParam.put("secret", miniAppSecret);
+        } else if (mode == 2) {
+            // 收款工具小程序appId
+            requestUrlParam.put("appid", receiptAppId);
+            log.info("收款工具小程序appId: ---" + receiptAppId);
+            // 收款工具小程序appSecret
+            requestUrlParam.put("secret", receiptAppSecret);
         } else {
             // 呵呵商城小程序appId
             requestUrlParam.put("appid", heHeAppId);

+ 83 - 0
src/main/java/com/caimei365/order/controller/ReceiptApi.java

@@ -0,0 +1,83 @@
+package com.caimei365.order.controller;
+
+import com.caimei365.order.model.ResponseJson;
+import com.caimei365.order.model.dto.ReceiptAuthDto;
+import com.caimei365.order.model.dto.ReceiptDto;
+import com.caimei365.order.model.vo.DiscernReceiptVo;
+import com.caimei365.order.model.vo.ReceiptUserVo;
+import com.caimei365.order.service.ReceiptService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpHeaders;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 线下收款接口
+ *
+ * @author : Charles
+ * @date : 2022/2/11
+ */
+@Api(tags="线下收款API")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/order/receipt")
+public class ReceiptApi {
+    private final ReceiptService receiptService;
+
+    /**
+     * 线下收款用户微信授权,用户数据存入Redis,key前缀:wxInfo:receipt:
+     *
+     * @param receiptAuthDto {
+     *                           code          微信授权code
+     *                           encryptedData 微信加密数据
+     *                           iv            加密算法的初始向量
+     *                       }
+     */
+    @ApiOperation("线下收款用户微信授权(小程序)")
+    @PostMapping("/auth")
+    public ResponseJson<ReceiptUserVo> receiptAuthorization(ReceiptAuthDto receiptAuthDto, @RequestHeader HttpHeaders headers) {
+        String code = receiptAuthDto.getCode();
+        String encryptedData = receiptAuthDto.getEncryptedData();
+        String iv = receiptAuthDto.getIv();
+        if (!StringUtils.hasLength(code)) {
+            return ResponseJson.error("没有获取到微信授权code", null);
+        }
+        return receiptService.receiptAuthorization(code, encryptedData, iv, headers);
+    }
+
+    @ApiOperation("线下收款用户密码登录")
+    @PostMapping("/password")
+    public ResponseJson<ReceiptUserVo> passwordAuthorization(ReceiptAuthDto receiptAuthDto, @RequestHeader HttpHeaders headers) {
+        String mobile = receiptAuthDto.getMobile();
+        String password = receiptAuthDto.getPassword();
+        String code = receiptAuthDto.getCode();
+        String encryptedData = receiptAuthDto.getEncryptedData();
+        String iv = receiptAuthDto.getIv();
+        if (!StringUtils.hasLength(code)) {
+            return ResponseJson.error("没有获取到微信授权code", null);
+        }
+        if (StringUtils.hasLength(mobile) && StringUtils.hasLength(password)){
+            return receiptService.passwordAuthorization(mobile, password, code, encryptedData, iv,  headers);
+        } else {
+            return ResponseJson.error("手机号或密码不能为空", null);
+        }
+    }
+
+    @ApiOperation("识别收款短信")
+    @PostMapping("/read/sms")
+    public ResponseJson<DiscernReceiptVo> readSmsMessage(ReceiptDto receiptDto) {
+        String message = receiptDto.getMessage();
+        if (StringUtils.hasLength(message)) {
+            return receiptService.readSmsMessage(message, receiptDto.getOpenid());
+        } else {
+            return ResponseJson.error("收款短信不能为空", null);
+        }
+    }
+
+}
+

+ 42 - 0
src/main/java/com/caimei365/order/mapper/ReceiptMapper.java

@@ -0,0 +1,42 @@
+package com.caimei365.order.mapper;
+
+import com.caimei365.order.model.enums.ReceivablesType;
+import com.caimei365.order.model.vo.DiscernReceiptVo;
+import com.caimei365.order.model.vo.ReceiptUserVo;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2022/2/11
+ */
+@Mapper
+public interface ReceiptMapper {
+    /**
+     * 根据openid获取收款用户
+     */
+    ReceiptUserVo getReceiptUserByOpenid(String openId);
+    /**
+     * 根据mobile获取收款用户
+     */
+    ReceiptUserVo getReceiptUserByMobile(String mobile);
+    /**
+     * 根据mobile更新openid
+     */
+    void updateOpenidByMobile(String openId, String mobile);
+    /**
+     * 获取用户权限: 1录入收款权限,2收款确认权限,3收款审核权限 4返佣管理权限 5供应商退款管理权限
+     */
+    List<Integer> getPermissionsByUserId(Integer userId);
+    /**
+     * 短信内容Md5加密串 获取收款记录
+     */
+    List<DiscernReceiptVo> getReceiptBySmsMd5Code(String smsMd5Code);
+    /**
+     * 获取收款类型
+     */
+    Integer getReceivablesTypeId(String type);
+}

+ 46 - 0
src/main/java/com/caimei365/order/model/dto/ReceiptAuthDto.java

@@ -0,0 +1,46 @@
+package com.caimei365.order.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2022/2/11
+ */
+@ApiModel("线下收款微信授权")
+@Data
+public class ReceiptAuthDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 微信授权code
+     */
+    @NotNull
+    @ApiModelProperty("微信授权code")
+    private String code;
+    /**
+     * 微信加密数据
+     */
+    @ApiModelProperty("微信加密数据")
+    private String encryptedData;
+    /**
+     * 加密算法的初始向量
+     */
+    @ApiModelProperty("加密算法的初始向量")
+    private String iv;
+    /**
+     * 授权人手机号
+     */
+    @ApiModelProperty("授权人手机号")
+    private String mobile;
+    /**
+     * 密码
+     */
+    @ApiModelProperty("密码")
+    private String password;
+}

+ 31 - 0
src/main/java/com/caimei365/order/model/dto/ReceiptDto.java

@@ -0,0 +1,31 @@
+package com.caimei365.order.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2022/2/11
+ */
+@ApiModel("款项")
+@Data
+public class ReceiptDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 微信openid
+     */
+    @ApiModelProperty("微信openid")
+    private String openid;
+    /**
+     * 收款短信
+     */
+    @NotNull
+    @ApiModelProperty("收款短信")
+    private String message;
+}

+ 3 - 1
src/main/java/com/caimei365/order/model/enums/ReceivablesType.java

@@ -25,7 +25,9 @@ public enum ReceivablesType {
     PCWX(13, "微信支付"),
     ZHIFUBAO(14, "支付宝"),
     MINIWX(15, "微信支付"),
-    YUEDIKO(16, "余额抵扣");
+    YUEDIKO(16, "余额抵扣"),
+    JIANSHE_1(18,"建设银行-1854"),
+    JIANSHE_2(19,"建设银行-6256");
 
     private final int code;
     private final String desc;

+ 20 - 0
src/main/java/com/caimei365/order/model/vo/DiscernReceiptVo.java

@@ -73,4 +73,24 @@ public class DiscernReceiptVo implements Serializable {
      * 米花科技平台唯一流水号
      */
     private String mbOrderId;
+    /**
+     * 短信内容
+     */
+    private String smsContent;
+    /**
+     * 短信内容Md5加密串(适用于二次短信匹配查询)
+     */
+    private String smsMd5Code;
+    /**
+     * 【扩展属性】是否存在手续费
+     */
+    private Boolean tipFeeFlag;
+    /**
+     * 【扩展属性】手续费
+     */
+    private Double tipFee;
+    /**
+     * 【扩展属性】订单标识
+     */
+    private String orderFlag;
 }

+ 48 - 0
src/main/java/com/caimei365/order/model/vo/ReceiptUserVo.java

@@ -0,0 +1,48 @@
+package com.caimei365.order.model.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2022/2/11
+ */
+@Data
+public class ReceiptUserVo implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 收款用户Id
+     */
+    @ApiModelProperty("收款用户Id")
+    private Integer id;
+    /**
+     * 用户类型:1协销人员,2客服,3财务,4超级管理员
+     */
+    @ApiModelProperty("用户类型:1协销人员,2客服,3财务,4超级管理员")
+    private Integer userType;
+    /**
+     * 名称
+     */
+    @ApiModelProperty("名称")
+    private String name;
+    /**
+     * 授权人手机号
+     */
+    @ApiModelProperty("授权人手机号")
+    private String mobile;
+    /**
+     * 微信openid
+     */
+    @ApiModelProperty("微信openid")
+    private String openid;
+    /**
+     * 密码
+     */
+    @ApiModelProperty("密码")
+    private String password;
+
+}

+ 36 - 0
src/main/java/com/caimei365/order/service/ReceiptService.java

@@ -0,0 +1,36 @@
+package com.caimei365.order.service;
+
+import com.caimei365.order.model.ResponseJson;
+import com.caimei365.order.model.vo.DiscernReceiptVo;
+import com.caimei365.order.model.vo.ReceiptUserVo;
+import org.springframework.http.HttpHeaders;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2022/2/11
+ */
+public interface ReceiptService {
+    /**
+     * 线下收款用户微信授权,用户数据存入Redis,key前缀:wxInfo:receipt:
+     * @param code          微信授权code
+     * @param encryptedData 微信加密数据
+     * @param iv            加密算法的初始向量
+     * @return receiptUser
+     */
+    ResponseJson<ReceiptUserVo> receiptAuthorization(String code, String encryptedData, String iv, HttpHeaders headers);
+    /**
+     * 线下收款用户密码登录
+     * @param mobile   手机号
+     * @param password 密码
+     */
+    ResponseJson<ReceiptUserVo> passwordAuthorization(String mobile, String password, String code, String encryptedData, String iv, HttpHeaders headers);
+    /**
+     * 识别收款短信
+     * @param message 收款短信
+     */
+    ResponseJson<DiscernReceiptVo> readSmsMessage(String message, String openid);
+
+
+}

+ 281 - 0
src/main/java/com/caimei365/order/service/impl/ReceiptServiceImpl.java

@@ -0,0 +1,281 @@
+package com.caimei365.order.service.impl;
+
+import com.caimei365.order.components.WeChatService;
+import com.caimei365.order.mapper.ReceiptMapper;
+import com.caimei365.order.model.ResponseJson;
+import com.caimei365.order.model.vo.DiscernReceiptVo;
+import com.caimei365.order.model.vo.ReceiptUserVo;
+import com.caimei365.order.service.ReceiptService;
+import com.caimei365.order.utils.DateUtils;
+import com.caimei365.order.utils.MathUtil;
+import com.caimei365.order.utils.Md5Util;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.http.HttpHeaders;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2022/2/11
+ */
+@Slf4j
+@Service
+public class ReceiptServiceImpl implements ReceiptService {
+    @Resource
+    private WeChatService weChatService;
+    @Resource
+    private ReceiptMapper receiptMapper;
+    /**
+     * 只有当识别出来的收款类型是广发银行-5461 ,中信银行-0897,中信银行0897-财付通 和 中信银行0897-支付宝时,才会显示手续费,并且自动勾选上手续费,默认按收款金额的千分之一计算 (收款金额 - 手续费 = 短信中收到的金额)
+     */
+    private static final List<Integer> tipFeeType = Arrays.asList(4, 5, 6, 11);
+    private static final Pattern PATTERN_NUMBER = Pattern.compile("[\\*0-9\\.:]+");
+    private static final Pattern PATTERN_ORDER = Pattern.compile("#(.*?)#");
+
+    /**
+     * 线下收款用户微信授权
+     *
+     * @param code          微信授权code
+     * @param encryptedData 微信加密数据
+     * @param iv            加密算法的初始向量
+     * @return receiptUser
+     */
+    @Override
+    public ResponseJson<ReceiptUserVo> receiptAuthorization(String code, String encryptedData, String iv, HttpHeaders headers) {
+        // 小程序微信授权获取登录信息
+        ResponseJson<Map<String, Object>> appletsInfo = weChatService.getInfoMapByApplets(code, headers, 2);
+        if (appletsInfo.getCode() == -1) {
+            return ResponseJson.error(appletsInfo.getMsg(), null);
+        }
+        Map<String, Object> infoData = appletsInfo.getData();
+        String openid = (String) infoData.get(WeChatService.Keys.OPEN_ID);
+        if (StringUtils.isNotBlank(openid)) {
+            // 收款用户
+            ReceiptUserVo receiptUser = receiptMapper.getReceiptUserByOpenid(openid);
+            if (null != receiptUser) {
+                return ResponseJson.success(receiptUser);
+            }
+        }
+        return ResponseJson.error("微信授权失败,请尝试账号密码登录!",null);
+    }
+
+    /**
+     * 线下收款用户密码登录
+     *
+     * @param mobile   手机号
+     * @param password 密码
+     */
+    @Override
+    public ResponseJson<ReceiptUserVo> passwordAuthorization(String mobile, String password, String code, String encryptedData, String iv,  HttpHeaders headers) {
+        // 收款用户
+        ReceiptUserVo receiptUser = receiptMapper.getReceiptUserByMobile(mobile);
+        if (null != receiptUser) {
+            // 比对密码
+            String md5Password = Md5Util.md5(password);
+            String dbPassword = receiptUser.getPassword();
+            if (md5Password.equals(dbPassword)) {
+                // 小程序微信授权获取登录信息
+                ResponseJson<Map<String, Object>> appletsInfo = weChatService.getInfoMapByApplets(code, headers, 2);
+                if (appletsInfo.getCode() != -1) {
+                    Map<String, Object> infoData = appletsInfo.getData();
+                    String openid = (String) infoData.get(WeChatService.Keys.OPEN_ID);
+                    receiptMapper.updateOpenidByMobile(openid, mobile);
+                    receiptUser.setOpenid(openid);
+                } else {
+                    return ResponseJson.error(appletsInfo.getMsg(), null);
+                }
+                return ResponseJson.success(receiptUser);
+            }
+        }
+        return ResponseJson.error("登录失败!",null);
+    }
+
+    /**
+     * 识别收款短信
+     * @param message 收款短信
+     */
+    @Override
+    public ResponseJson<DiscernReceiptVo> readSmsMessage(String message, String openid) {
+        // 收款用户
+        ReceiptUserVo receiptUser = receiptMapper.getReceiptUserByOpenid(openid);
+        if (null != receiptUser) {
+            // 获取用户权限: 1录入收款权限,2收款确认权限,3收款审核权限 4返佣管理权限 5供应商退款管理权限
+            List<Integer> permissions = receiptMapper.getPermissionsByUserId(receiptUser.getId());
+            if (permissions.contains(1)) {
+                try {
+                    // 识别短信内容
+                    ResponseJson<DiscernReceiptVo> receipt = identifyMessage(message);
+                    if (receipt != null) {
+                        return receipt ;
+                    }
+                } catch (Exception e) {
+                    log.error("短信识别错误!", e);
+                    return ResponseJson.error("短信识别错误!", null);
+                }
+            }
+        }
+        return ResponseJson.error("无权限操作!", null);
+    }
+
+    /**
+     * 识别收款短信
+     * 以下方法按照短信采样结果实现(新增短信不兼容)
+     *
+     * @param message 收款短信
+     * 贵公司尾号7297的账户5月23日15时30分往来款收入人民币1800.00元,余额7055.50元。对方户名:哈尔滨爱丽达医疗美容管理有限公司爱建医疗美容诊所。[建设银行]
+     * 【广发银行】尊敬的客户,贵司账号后四位0115 的账户于08日13:55收入一笔方芳尾数为8067的账户转账1850.00元,手续费0.00元。账户余额:1000000.00元。
+     * 【广发银行】您末四位为0115的企业账户于12日16:09收入人民币5000.00元(深圳同城)。账户余额:8907.21元。
+     * 【中信银行】贵公司尾号7172的中信账号于03月15日17:25,二代支付存入人民币3132.30元,当前余额为人民币4373.07元。
+     * 【中信银行】您尾号0897的中信卡于03月06日11:44,存入人民币2358.00元,当前余额为人民币1000000.00元。
+     * 【中信银行】您尾号0897的中信卡于03月19日13:37,财付通快捷支付存入人民币11348.45元,当前余额为人民币1000000.00元。
+     * 【中信银行】您尾号0897的中信卡于03月14日16:01,支付宝存入人民币5994.06元,当前余额为人民币1000000.00元。
+     * 【中信银行】您尾号0897的中信卡于05月29日14:42,二代支付存入人民币10000.00元,当前余额为人民币13871.67元。
+     */
+    private ResponseJson<DiscernReceiptVo> identifyMessage(String message) throws Exception {
+        message = message.replace(":", ":").trim();
+        if (message.contains("银行")) {
+            /*隐藏余额后去数据库进行全匹配*/
+            int index = message.indexOf("余额");
+            if (index != -1) {
+                int index2 = message.indexOf("元", index);
+                String text1 = message.substring(0, index + 2);
+                String text2 = message.substring(index2);
+                message = text1 + "***" + text2;
+            }
+            String md5Msg = Md5Util.md5(message);
+            /*查询数据库,是否存在短信记录,存在就直接读取数据并返回*/
+            List<DiscernReceiptVo> receiptList = receiptMapper.getReceiptBySmsMd5Code(md5Msg);
+            if (!CollectionUtils.isEmpty(receiptList)){
+                receiptList.get(0).setTipFeeFlag(tipFeeType.contains(receiptList.get(0).getPayType()));
+                return ResponseJson.success(receiptList.get(0));
+            }
+
+            // 数据库不存在短信记录,执行下面的操作
+            /*识别收款类别*/
+            index = message.indexOf("银行");
+            String receivableDesc = message.substring(index - 2, index + 2);
+            if (receivableDesc.contains("中信银行")) {
+                index = message.indexOf("尾号");
+                String account = message.substring(index + 2, index + 2 + 4);
+                receivableDesc = receivableDesc + "-" + account;
+                if (message.contains("财付通")) {
+                    receivableDesc += "-财付通";
+                }
+                if (message.contains("支付宝")) {
+                    receivableDesc += "-支付宝";
+                }
+            }else if (receivableDesc.contains("广发银行") || receivableDesc.contains("建设银行")) {
+                // 匹配的第一组数字为银行卡尾号
+                Matcher matcherBank = PATTERN_NUMBER.matcher(message);
+                if (matcherBank.find()) {
+                    receivableDesc = receivableDesc + "-" + matcherBank.group();
+                }
+            }
+            Integer typeId = receiptMapper.getReceivablesTypeId(receivableDesc);
+
+            /*识别收款时间*/
+            String time = "";
+            String year = DateUtils.getYear();
+            String month = DateUtils.getMonth();
+            List<String> contentTime = new ArrayList();
+            Matcher matcher = PATTERN_NUMBER.matcher(message);
+            while (matcher.find()) {
+                String group = matcher.group();
+                contentTime.add(group);
+            }
+            // 建设银行
+            if (Arrays.asList(1, 18, 19).contains(typeId)){
+                time = year + "-" + contentTime.get(1) + "-" + contentTime.get(2) + " " + contentTime.get(3) + ":" + contentTime.get(4) + ":" + "00";
+                int difference = DateUtils.differentDays(time);
+                if (difference < 0) {
+                    time = Integer.parseInt(year) - 1 + "-" + contentTime.get(1) + "-" + contentTime.get(2) + " " + contentTime.get(3) + ":" + contentTime.get(4) + ":" + "00";
+                }
+            }
+            // 广发银行
+            else if (Arrays.asList(2, 11).contains(typeId)){
+                time = year + "-" + month + "-" + contentTime.get(1) + " " + contentTime.get(2) + ":" + "00";
+                int difference = DateUtils.differentDays(time);
+                /* 差距大于30天 减一年, 小于30天 减一个月 */
+                if (difference < -30) {
+                    time = Integer.parseInt(year) - 1 + "-" + month + "-" + contentTime.get(1) + " " + contentTime.get(2) + ":" + contentTime.get(3) + ":" + "00";
+                } else if (difference < 0) {
+                    time = DateUtils.format(DateUtils.addMonth(DateUtils.parseDate(time), -1), "yyyy-MM-dd HH:mm:ss");
+                }
+            } else {
+                time = year + "-" + contentTime.get(1) + "-" + contentTime.get(2) + " " + contentTime.get(3) + ":" + "00";
+                int difference = DateUtils.differentDays(time);
+                if (difference < 0) {
+                    time = Integer.parseInt(year) - 1 + "-" + contentTime.get(1) + "-" + contentTime.get(2) + " " + contentTime.get(3) + ":" + "00";
+                }
+            }
+
+            /*识别收款金额*/
+            double money = 0d;
+            if (typeId == 2) {
+                // 广发银行
+                if (message.contains("入人民币")) {
+                    index = message.indexOf("入人民币");
+                    int index2 = message.indexOf("元", index);
+                    money = Double.parseDouble(message.substring(index + 4, index2));
+                } else if (message.contains("账户转账")) {
+                    index = message.indexOf("账户转账");
+                    int index2 = message.indexOf("元", index);
+                    money = Double.parseDouble(message.substring(index + 4, index2));
+                }
+            } else {
+                if (message.contains("入人民币")) {
+                    index = message.indexOf("入人民币");
+                    int index2 = message.indexOf("元", index);
+                    money = Double.parseDouble(message.substring(index + 4, index2));
+                } else {
+                    throw new Exception("短信识别错误!");
+                }
+            }
+
+            /*识别手续费*/
+            boolean tipFeeFlag = false;
+            double tipFee = 0d;
+            if (tipFeeType.contains(typeId)) {
+                tipFeeFlag = true;
+                tipFee = MathUtil.mul(money, MathUtil.div(1, 1000), 2).doubleValue();
+                // 收款金额 = 短信收款金额+手续费
+                money = MathUtil.add(money, tipFee).doubleValue();
+            }
+
+            /*识别订单标识*/
+            String orderFlag = "";
+            Matcher matcherOrder = PATTERN_ORDER.matcher(message);
+            if (matcherOrder.find()) {
+                orderFlag = matcherOrder.group(1);
+            }
+
+            // 线下收款
+            DiscernReceiptVo receipt = new DiscernReceiptVo();
+            receipt.setPayWay(2);
+            receipt.setPayType(typeId);
+            receipt.setReceiptDate(time);
+            receipt.setReceiptAmount(money);
+            receipt.setTipFeeFlag(tipFeeFlag);
+            receipt.setTipFee(tipFee);
+            receipt.setOrderFlag(orderFlag);
+            receipt.setSmsMd5Code(md5Msg);
+            receipt.setSmsContent(message);
+
+            return ResponseJson.success(receipt);
+        }
+        return ResponseJson.error("短信识别错误!", null);
+    }
+
+
+}

+ 785 - 0
src/main/java/com/caimei365/order/utils/DateUtils.java

@@ -0,0 +1,785 @@
+package com.caimei365.order.utils;
+
+import org.apache.commons.lang3.time.DateFormatUtils;
+
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+/**
+ * 日期工具类, 继承org.apache.commons.lang3.time.DateUtils类
+ * @author LG
+ * @date  2016年3月22日
+ * @version 1.0
+ */
+public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
+
+
+	//fixme lwt  已经与www的 DateUtils 整合
+	/**
+	 * 英文简写(默认)如:2010-12-01
+	 */
+	public static String FORMAT_SHORT = "yyyy-MM-dd";
+
+	/**
+	 * 得到当前日期字符串 格式(yyyy-MM-dd)
+	 */
+	public static String getDate() {
+		return getDate("yyyy-MM-dd");
+	}
+
+	private static String[] parsePatterns = {
+			"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
+			"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
+			"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
+
+	/**
+	 * 得到当前日期字符串 格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E"
+	 */
+	public static String getDate(String pattern) {
+		return DateFormatUtils.format(new Date(), pattern);
+	}
+
+	/**
+	 * 得到日期字符串 默认格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E"
+	 */
+	public static String formatDate(Date date, Object... pattern) {
+		String formatDate = null;
+		if (pattern != null && pattern.length > 0) {
+			formatDate = DateFormatUtils.format(date, pattern[0].toString());
+		} else {
+			formatDate = DateFormatUtils.format(date, "yyyy-MM-dd");
+		}
+		return formatDate;
+	}
+
+	/**
+	 * 得到日期时间字符串,转换格式(yyyy-MM-dd HH:mm:ss)
+	 */
+	public static String formatDateTime(Date date) {
+		return formatDate(date, "yyyy-MM-dd HH:mm:ss");
+	}
+
+	/**
+	 * 得到当前时间字符串 格式(HH:mm:ss)
+	 */
+	public static String getTime() {
+		return formatDate(new Date(), "HH:mm:ss");
+	}
+
+	/**
+	 * 得到当前日期和时间字符串 格式(yyyy-MM-dd HH:mm:ss)
+	 */
+	public static String getDateTime() {
+		return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
+	}
+
+	/**
+	 * 得到当前年份字符串 格式(yyyy)
+	 */
+	public static String getYear() {
+		return formatDate(new Date(), "yyyy");
+	}
+
+	/**
+	 * 得到当前月份字符串 格式(MM)
+	 */
+	public static String getMonth() {
+		return formatDate(new Date(), "MM");
+	}
+
+	/**
+	 * 得到当天字符串 格式(dd)
+	 */
+	public static String getDay() {
+		return formatDate(new Date(), "dd");
+	}
+
+	/**
+	 * 得到当前星期字符串 格式(E)星期几
+	 */
+	public static String getWeek() {
+		return formatDate(new Date(), "E");
+	}
+
+	/**
+	 * 日期型字符串转化为日期 格式
+	 * { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm",
+	 *   "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm",
+	 *   "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm" }
+	 */
+	public static Date parseDate(Object str) {
+		if (str == null){
+			return null;
+		}
+		try {
+			return parseDate(str.toString(), parsePatterns);
+		} catch (ParseException e) {
+			return null;
+		}
+	}
+
+	/**
+	 * 获取过去的天数
+	 * @param date
+	 * @return
+	 */
+	public static long pastDays(Date date) {
+		long t = new Date().getTime()-date.getTime();
+		return t/(24*60*60*1000);
+	}
+
+	/**
+	 * 获取过去的小时
+	 * @param date
+	 * @return
+	 */
+	public static long pastHour(Date date) {
+		long t = new Date().getTime()-date.getTime();
+		return t/(60*60*1000);
+	}
+
+	/**
+	 * 获取过去的分钟
+	 * @param date
+	 * @return
+	 */
+	public static long pastMinutes(Date date) {
+		long t = new Date().getTime()-date.getTime();
+		return t/(60*1000);
+	}
+
+	/**
+	 * 转换为时间(天,时:分:秒.毫秒)
+	 * @param timeMillis
+	 * @return
+	 */
+    public static String formatDateTime(long timeMillis){
+		long day = timeMillis/(24*60*60*1000);
+		long hour = (timeMillis/(60*60*1000)-day*24);
+		long min = ((timeMillis/(60*1000))-day*24*60-hour*60);
+		long s = (timeMillis/1000-day*24*60*60-hour*60*60-min*60);
+		long sss = (timeMillis-day*24*60*60*1000-hour*60*60*1000-min*60*1000-s*1000);
+		return (day>0?day+",":"")+hour+":"+min+":"+s+"."+sss;
+    }
+
+	/**
+	 * 获取两个日期之间的天数
+	 *
+	 * @param before
+	 * @param after
+	 * @return
+	 */
+	public static double getDistanceOfTwoDate(Date before, Date after) {
+		long beforeTime = before.getTime();
+		long afterTime = after.getTime();
+		return (afterTime - beforeTime) / (1000 * 60 * 60 * 24);
+	}
+
+	/**
+	 * 获取某个月的天数
+	 * @param date
+	 * @return
+	 */
+	public static int getDaysOfMonth(Date date) {
+		Calendar calendar = Calendar.getInstance();
+		calendar.setTime(date);
+		return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
+	}
+
+	/**
+	 * 在日期上增加天数
+	 *
+	 * @param date
+	 *            日期
+	 * @param n
+	 *            要增加的天数
+	 * @return
+	 */
+	public static Date addDay(Date date, int n) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(date);
+		cal.add(Calendar.DATE, n);
+		return cal.getTime();
+	}
+
+//	/**
+//	 * @param args
+//	 * @throws ParseException
+//	 */
+//	public static void main(String[] args) throws ParseException {
+//		System.out.println(formatDate(parseDate("2010/3/6")));
+//		System.out.println(getDate("yyyy年MM月dd日 E"));
+//		long time = new Date().getTime()-parseDate("2012-11-19").getTime();
+//		System.out.println(time/(24*60*60*1000));
+//	}
+
+	/**
+	 * 英文全称 如:2010-12-01 23:15:06
+	 */
+	public static String FORMAT_LONG = "yyyy-MM-dd HH:mm:ss";
+	/**
+	 * 精确到毫秒的完整时间 如:yyyy-MM-dd HH:mm:ss.S
+	 */
+	public static String FORMAT_FULL = "yyyy-MM-dd HH:mm:ss.S";
+	/**
+	 * 中文简写 如:2010年12月01日
+	 */
+	public static String FORMAT_SHORT_CN = "yyyy年MM月dd";
+	/**
+	 * 中文全称 如:2010年12月01日 23时15分06秒
+	 */
+	public static String FORMAT_LONG_CN = "yyyy年MM月dd日  HH时mm分ss秒";
+	/**
+	 * 精确到毫秒的完整中文时间
+	 */
+	public static String FORMAT_FULL_CN = "yyyy年MM月dd日  HH时mm分ss秒SSS毫秒";
+
+	/**
+	 * 获得默认的 date pattern
+	 */
+	public static String getDatePattern() {
+		return FORMAT_LONG;
+	}
+
+	/**
+	 * 根据预设格式返回当前日期
+	 *
+	 * @return
+	 */
+	public static String getNow() {
+		return format(new Date());
+	}
+
+	/**
+	 * 根据用户格式返回当前日期
+	 *
+	 * @param format
+	 * @return
+	 */
+	public static String getNow(String format) {
+		return format(new Date(), format);
+	}
+
+	/**
+	 * 使用预设格式格式化日期
+	 *
+	 * @param date
+	 * @return
+	 */
+	public static String format(Date date) {
+		return format(date, getDatePattern());
+	}
+
+	/**
+	 * 使用用户格式格式化日期
+	 *
+	 * @param date
+	 *            日期
+	 * @param pattern
+	 *            日期格式
+	 * @return
+	 */
+	public static String format(Date date, String pattern) {
+		String returnValue = "";
+		if (date != null) {
+			SimpleDateFormat df = new SimpleDateFormat(pattern);
+			returnValue = df.format(date);
+		}
+		return (returnValue);
+	}
+
+	/**
+	 * 使用预设格式提取字符串日期
+	 *
+	 * @param strDate
+	 *            日期字符串
+	 * @return
+	 */
+	public static Date parse(String strDate) {
+		return parse(strDate, getDatePattern());
+	}
+
+	/**
+	 * 使用用户格式提取字符串日期
+	 *
+	 * @param strDate
+	 *            日期字符串
+	 * @param pattern
+	 *            日期格式
+	 * @return
+	 */
+	public static Date parse(String strDate, String pattern) {
+		SimpleDateFormat df = new SimpleDateFormat(pattern);
+		try {
+			return df.parse(strDate);
+		} catch (ParseException e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+
+	/**
+	 * 在日期上增加数个整月
+	 *
+	 * @param date
+	 *            日期
+	 * @param n
+	 *            要增加的月数
+	 * @return
+	 */
+	public static Date addMonth(Date date, int n) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(date);
+		cal.add(Calendar.MONTH, n);
+		return cal.getTime();
+	}
+
+	/**
+	 * 在日期上增加描述
+	 *
+	 * @param date
+	 *            日期
+	 * @param n
+	 *            要增加的天数
+	 * @return
+	 */
+	public static Date addSecond(Date date, int n) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(date);
+		cal.add(Calendar.SECOND, n);
+		return cal.getTime();
+	}
+
+	/**
+	 * 获取时间戳
+	 */
+	public static String getTimeString() {
+		SimpleDateFormat df = new SimpleDateFormat(FORMAT_FULL);
+		Calendar calendar = Calendar.getInstance();
+		return df.format(calendar.getTime());
+	}
+
+	/**
+	 * 获取日期年份
+	 *
+	 * @param date
+	 *            日期
+	 * @return
+	 */
+	public static String getYear(Date date) {
+		return format(date).substring(0, 4);
+	}
+
+	/**
+	 * 按默认格式的字符串距离今天的天数
+	 *
+	 * @param date
+	 *            日期字符串
+	 * @return
+	 */
+	public static int countDays(String date) {
+		long t = Calendar.getInstance().getTime().getTime();
+		Calendar c = Calendar.getInstance();
+		c.setTime(parse(date));
+		long t1 = c.getTime().getTime();
+		return (int) (t / 1000 - t1 / 1000) / 3600 / 24;
+	}
+
+	/**
+	 * 按用户格式字符串距离今天的天数(超过24小时才可以使用)
+	 *
+	 * @param date
+	 *            日期字符串
+	 * @param format
+	 *            日期格式
+	 * @return
+	 */
+	public static int countDays(String date, String format) {
+		long t = Calendar.getInstance().getTime().getTime();
+		Calendar c = Calendar.getInstance();
+		c.setTime(parse(date, format));
+		long t1 = c.getTime().getTime();
+		return (int) (t / 1000 - t1 / 1000) / 3600 / 24;
+	}
+
+	public static String firstDayOfMonth(Date date){
+		Calendar calendar = Calendar.getInstance();
+		calendar.setTime(date);
+		calendar.set(Calendar.DAY_OF_MONTH, calendar
+				.getActualMinimum(Calendar.DAY_OF_MONTH));
+		calendar.set(Calendar.HOUR_OF_DAY, 0);
+		calendar.set(Calendar.SECOND,0);
+		calendar.set(Calendar.MINUTE,0);
+		return DateUtils.format(calendar.getTime());
+	}
+
+	public static String lastDayOfMonth(Date date){
+		Calendar calendar = Calendar.getInstance();
+		calendar.setTime(date);
+		calendar.set(Calendar.DAY_OF_MONTH, calendar
+				.getActualMaximum(Calendar.DAY_OF_MONTH));
+		calendar.set(Calendar.HOUR_OF_DAY, 23);
+		calendar.set(Calendar.SECOND,59);
+		calendar.set(Calendar.MINUTE,59);
+		return DateUtils.format(calendar.getTime());
+	}
+
+	public static int currentMonth(){
+		Calendar calendar = Calendar.getInstance();
+		return calendar.get(Calendar.MONTH)+1;
+	}
+
+	public static int currentYear(){
+		Calendar calendar = Calendar.getInstance();
+		return calendar.get(Calendar.YEAR);
+	}
+
+	public static int currentMonthLastDay(){
+		Calendar calendar = Calendar.getInstance();
+		calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
+		return calendar.get(Calendar.DAY_OF_MONTH);
+	}
+
+	public static int LastDayOfMonth(Date date){
+		Calendar calendar = Calendar.getInstance();
+		calendar.setTime(date);
+		calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
+		return calendar.get(Calendar.DAY_OF_MONTH);
+	}
+
+	public static int getDay4Date(Date date){
+		Calendar calendar = Calendar.getInstance();
+		calendar.setTime(date);
+		return calendar.get(Calendar.DAY_OF_MONTH);
+	}
+
+	public static boolean afterNow(Date date){
+		return new Date().before(date);
+	}
+
+//	/**
+//	 *
+//	 * @param agrs
+//	 * @throws ParseException
+//	 */
+//	public static void main(String[] agrs) throws ParseException {
+//		//System.out.println(DateUtils.format(DateUtils.parse("2015-5-19 10:49:29"), "yyyy年MM月"));
+//		System.out.println(DateUtils.firstDayOfMonth(parse("2015-02-01",FORMAT_SHORT)));
+//		System.out.println(DateUtils.lastDayOfMonth(parse("2015-02-01",FORMAT_SHORT)));
+//		System.out.println(currentYear());
+//		System.out.println(currentMonthLastDay());
+//	}
+
+	// 获取上周的开始时间
+	@SuppressWarnings("unused")
+	public static Date getBeginDayOfLastWeek() {
+		Date date = new Date();
+		if (date == null) {
+			return null;
+		}
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(date);
+		int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
+		if (dayofweek == 1) {
+			dayofweek += 7;
+		}
+		cal.add(Calendar.DATE, 2 - dayofweek - 7);
+		return getDayStartTime(cal.getTime());
+	}
+
+	// 获取上周的结束时间
+	public static Date getEndDayOfLastWeek() {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(getBeginDayOfLastWeek());
+		cal.add(Calendar.DAY_OF_WEEK, 6);
+		Date weekEndSta = cal.getTime();
+		return getDayEndTime(weekEndSta);
+	}
+
+	// 获取某个日期的开始时间
+	public static Timestamp getDayStartTime(Date d) {
+		Calendar calendar = Calendar.getInstance();
+		if (null != d) {
+			calendar.setTime(d);
+		}
+		calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
+				calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+		calendar.set(Calendar.MILLISECOND, 0);
+		return new Timestamp(calendar.getTimeInMillis());
+	}
+
+	// 获取某个日期的结束时间
+	public static Timestamp getDayEndTime(Date d) {
+		Calendar calendar = Calendar.getInstance();
+		if (null != d) {
+			calendar.setTime(d);
+		}
+		calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
+				calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59);
+		calendar.set(Calendar.MILLISECOND, 999);
+		return new Timestamp(calendar.getTimeInMillis());
+	}
+
+	// 获取上月的开始时间
+	public static Date getBeginDayOfLastMonth() {
+		Calendar calendar = Calendar.getInstance();
+		calendar.set(getNowYear(), getNowMonth() - 2, 1);
+		return getDayStartTime(calendar.getTime());
+	}
+
+	// 获取上月的结束时间
+	public static Date getEndDayOfLastMonth() {
+		Calendar calendar = Calendar.getInstance();
+		calendar.set(getNowYear(), getNowMonth() - 2, 1);
+		int day = calendar.getActualMaximum(5);
+		calendar.set(getNowYear(), getNowMonth() - 2, day);
+		return getDayEndTime(calendar.getTime());
+	}
+
+	// 获取今年是哪一年
+	public static Integer getNowYear() {
+		Date date = new Date();
+		GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
+		gc.setTime(date);
+		return Integer.valueOf(gc.get(1));
+	}
+
+	// 获取本月是哪一月
+	public static int getNowMonth() {
+		Date date = new Date();
+		GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
+		gc.setTime(date);
+		return gc.get(2) + 1;
+	}
+
+	// 获取昨天的开始时间
+	public static Date getBeginDayOfYesterday() {
+		Calendar cal = new GregorianCalendar();
+		cal.setTime(getDayBegin());
+		cal.add(Calendar.DAY_OF_MONTH, -1);
+		return cal.getTime();
+	}
+
+	// 获取昨天的结束时间
+	public static Date getEndDayOfYesterDay() {
+		Calendar cal = new GregorianCalendar();
+		cal.setTime(getDayEnd());
+		cal.add(Calendar.DAY_OF_MONTH, -1);
+		return cal.getTime();
+	}
+
+	// 获取当天的开始时间
+	public static Date getDayBegin() {
+		Calendar cal = new GregorianCalendar();
+		cal.set(Calendar.HOUR_OF_DAY, 0);
+		cal.set(Calendar.MINUTE, 0);
+		cal.set(Calendar.SECOND, 0);
+		cal.set(Calendar.MILLISECOND, 0);
+		return cal.getTime();
+	}
+
+	// 获取当天的结束时间
+	public static Date getDayEnd() {
+		Calendar cal = new GregorianCalendar();
+		cal.set(Calendar.HOUR_OF_DAY, 23);
+		cal.set(Calendar.MINUTE, 59);
+		cal.set(Calendar.SECOND, 59);
+		return cal.getTime();
+	}
+
+	/**
+	 * @Author ye.qin
+	 * @Description //TODO 返回两个时间字符串的时间差(秒)
+	 * @Date 2018\12\29 0029 15:56
+	 * @Param
+	 * @return
+	 */
+	public static int betweenDate(String endTime,String startTime,String YMDHMS){
+		Date time1 = DateUtils.parse(endTime,YMDHMS);
+		Date time2 = DateUtils.parse(startTime,YMDHMS);
+		int a = (int) (time1.getTime() / 1000);
+		int b = (int) (time2.getTime() / 1000);
+		System.out.print(a-b);
+		return a-b;
+	}
+
+	/**
+	 * @Author ye.qin
+	 * @Description //TODO 获取指定格式的时间
+	 * @Date 2018\12\29 0029 16:26
+	 * @Param
+	 * @return
+	 */
+	public static String getTargetTime(String time,String YMDHMS,String targetFormat){
+		Date a = parse(time,YMDHMS);
+		String b = format(a,targetFormat);
+		return b;
+	}
+
+    /**
+     * date2比date1多的天数
+     * @param date
+     * @return
+     */
+    public static int differentDays(String date)
+    {
+        Calendar cal1 = Calendar.getInstance();
+        cal1.setTime(parseDate(date));
+
+        Calendar cal2 = Calendar.getInstance();
+        cal2.setTime(new Date());
+        int day1= cal1.get(Calendar.DAY_OF_YEAR);
+        int day2 = cal2.get(Calendar.DAY_OF_YEAR);
+
+        int year1 = cal1.get(Calendar.YEAR);
+        int year2 = cal2.get(Calendar.YEAR);
+        if(year1 != year2)
+        {
+            int timeDistance = 0 ;
+            for(int i = year1 ; i < year2 ; i ++)
+            {
+                if(i%4==0 && i%100!=0 || i%400==0)    //闰年
+                {
+                    timeDistance += 366;
+                }
+                else    //不是闰年
+                {
+                    timeDistance += 365;
+                }
+            }
+
+            return timeDistance + (day2-day1) ;
+        }
+        else
+        {
+            return day2-day1;
+        }
+    }
+
+	/**
+	 * @Author ye.qin
+	 * @Description //TODO 格式化文章时间
+	 * @Date 2019\1\14 0014 15:48
+	 * @Param
+	 * @return
+	 */
+	public static String getArticleTime(String deployTime, String YMDHMS) {
+		final String TARGETTIME = "yyyy年MM月dd日";
+		final String HOURMINUTE = "HH:mm";
+		String time1 = "";
+		String currentTime = DateUtils.format(new Date(),YMDHMS);
+		int minuteFlag = DateUtils.betweenDate(currentTime,deployTime,YMDHMS);
+		int dayFlag = DateUtils.differentDays(deployTime);
+		if(minuteFlag > 0){
+			if(minuteFlag < 3*60){
+				time1 = "刚刚";
+			}else if(minuteFlag < 5*60){
+				time1= "3分钟前";
+			}else if(minuteFlag < 10*60){
+				time1 = "5分钟前";
+			}else if(minuteFlag < 20*60){
+				time1 = "10分钟前";
+			}else if(minuteFlag < 30*60){
+				time1 = "20分钟前";
+			}else if(minuteFlag < 60*60){
+				time1 = "30分钟前";
+			}else if(dayFlag == 0){
+				time1 = "今天 "+DateUtils.getTargetTime(deployTime,YMDHMS,HOURMINUTE);
+			}else if(dayFlag == 1){
+				time1 = "昨天 "+DateUtils.getTargetTime(deployTime,YMDHMS,HOURMINUTE);
+			}else{
+				time1 = DateUtils.getTargetTime(deployTime,YMDHMS,TARGETTIME);
+			}
+
+		}
+		return time1;
+	}
+
+	public static String getDatePoor(Date endDate, Date nowDate) {
+
+		long nd = 1000 * 24 * 60 * 60;
+		long nh = 1000 * 60 * 60;
+		long nm = 1000 * 60;
+		// long ns = 1000;
+		// 获得两个时间的毫秒时间差异
+		long diff = endDate.getTime() - nowDate.getTime();
+		// 计算差多少天
+		long day = diff / nd;
+		// 计算差多少小时
+		long hour = diff % nd / nh;
+		// 计算差多少分钟
+		long min = diff % nd % nh / nm;
+		// 计算差多少秒//输出结果
+		// long sec = diff % nd % nh % nm / ns;
+		return day + "天" + hour + "小时" + min + "分钟";
+	}
+
+	public static String getHourPoor(Date endDate, Date nowDate) {
+
+
+		long nh = 1000 * 60 * 60;
+		long nm = 1000 * 60;
+		// long ns = 1000;
+		// 获得两个时间的毫秒时间差异
+		long diff = endDate.getTime() - nowDate.getTime();
+
+		// 计算差多少小时
+		long hour = diff  / nh;
+		// 计算差多少分钟
+		long min = diff  % nh / nm;
+		// 计算差多少秒//输出结果
+		// long sec = diff % nd % nh % nm / ns;
+		return  hour + "小时" + min + "分钟";
+	}
+
+	public static String getGroupEndTime(Date endTime,String YMDHMS) {
+		final String HOURMINUTE = "HH:mm";
+		String time = formatDate(endTime,YMDHMS);
+		String time1 = "";
+		String currentTime = DateUtils.format(new Date(),YMDHMS);
+		int minuteFlag = DateUtils.betweenDate(time,currentTime,YMDHMS);
+		int dayFlag = DateUtils.differentDays(time);
+		if(minuteFlag > 0){
+
+			if(minuteFlag < 60*60*24*3){
+				time1 = getHourPoor(endTime,new Date());
+			}else{
+				time1 = "剩余"+(-dayFlag)+"天";
+			}
+		}
+		return time1;
+	}
+
+	/**
+	 * @param nowTime   当前时间
+	 * @param startTime 开始时间
+	 * @param endTime   结束时间
+	 * @return
+	 * @author sunran   判断当前时间在时间区间内
+	 */
+	public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
+		if (nowTime.getTime() == startTime.getTime()
+				|| nowTime.getTime() == endTime.getTime()) {
+			return true;
+		}
+
+		Calendar date = Calendar.getInstance();
+		date.setTime(nowTime);
+
+		Calendar begin = Calendar.getInstance();
+		begin.setTime(startTime);
+
+		Calendar end = Calendar.getInstance();
+		end.setTime(endTime);
+
+		if (date.after(begin) && date.before(end)) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+}

+ 42 - 0
src/main/resources/mapper/ReceiptMapper.xml

@@ -0,0 +1,42 @@
+<?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.caimei365.order.mapper.ReceiptMapper">
+    <update id="updateOpenidByMobile">
+        UPDATE cm_receipt_user set openid=#{openid} WHERE mobile = #{mobile}
+    </update>
+    <select id="getReceiptUserByOpenid" resultType="com.caimei365.order.model.vo.ReceiptUserVo">
+        SELECT DISTINCT id, user_type AS userType, name, mobile, openid, password
+        FROM cm_receipt_user
+        WHERE openid = #{openid} AND del_flag = 0
+    </select>
+    <select id="getReceiptUserByMobile" resultType="com.caimei365.order.model.vo.ReceiptUserVo">
+        SELECT DISTINCT id, user_type AS userType, name, mobile, openid, password
+        FROM cm_receipt_user
+        WHERE mobile = #{mobile} AND del_flag = 0
+    </select>
+    <select id="getPermissionsByUserId" resultType="java.lang.Integer">
+        SELECT permission FROM cm_receipt_user_permission WHERE user_id = #{userId}
+    </select>
+    <select id="getReceiptBySmsMd5Code" resultType="com.caimei365.order.model.vo.DiscernReceiptVo">
+        SELECT DISTINCT
+            cdr.id,
+            cdr.payWay,
+            cdr.payType,
+            cdr.receiptType,
+            cdr.receiptStatus,
+            cdr.receiptAmount,
+            cdr.confirmType,
+            cdr.receiptDate,
+            cdr.confirmDate,
+            cdr.reviewDate,
+            cdr.updateDate,
+            cdr.delFlag,
+            cror.mbOrderId,
+            cror.associateAmount
+        FROM cm_receipt_order_relation cror LEFT JOIN cm_discern_receipt cdr ON cror.receiptID = cdr.id
+        WHERE cdr.smsMd5Code = #{smsMd5Code} AND cror.delFlag = '0' AND cdr.delFlag = '0'
+    </select>
+    <select id="getReceivablesTypeId" resultType="java.lang.Integer">
+        SELECT DISTINCT IFNULL(id, 0) FROM cm_receipt_type WHERE type=#{type}
+    </select>
+</mapper>