| @@ -125,6 +125,7 @@ public enum ErrorCode{ | |||
| NICK_NAME_NOT_FOUND(11004, "nickName,unionId未授权"), | |||
| PHONE_NOT_FOUND(11005, "Phone未授权"), | |||
| PHONE_IS_ENCRYPTED(11006, "Phone已加密"), | |||
| TEMPLATE_SEND_FAILED(11007, "模板消息发送失败"), | |||
| /** | |||
| @@ -166,8 +167,13 @@ public enum ErrorCode{ | |||
| * 解单 | |||
| */ | |||
| DALIY_REPORT_VOLUME_TODAY_NULL(12070, "今日解单不存在"), | |||
| DALIY_REPORT_VOLUME_WEEK_NULL(12071, "无解单数据") | |||
| ; | |||
| DALIY_REPORT_VOLUME_WEEK_NULL(12071, "无解单数据"), | |||
| /** | |||
| * 模板消息 | |||
| */ | |||
| TEMPLATE_NOT_FOUND(12090, "模板不存在") | |||
| ; | |||
| @@ -0,0 +1,152 @@ | |||
| package com.simple.domain.po; | |||
| import javax.persistence.*; | |||
| import java.util.*; | |||
| import java.math.*; | |||
| import javax.persistence.Transient; | |||
| import java.util.List; | |||
| import javax.persistence.Id; | |||
| import java.io.Serializable; | |||
| @Table(name = "wx_template_msg") | |||
| public class WxTemplateMsg implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| @Id | |||
| protected Long id; | |||
| @Transient | |||
| protected List<Long> ids; | |||
| @Transient | |||
| protected String sortColumns; | |||
| public Long getId() { | |||
| return id; | |||
| } | |||
| public void setId(Long id) { | |||
| this.id = id; | |||
| } | |||
| public String getSortColumns() { | |||
| return sortColumns; | |||
| } | |||
| public List<Long> getIds() { | |||
| return ids; | |||
| } | |||
| public void setIds(List<Long> ids) { | |||
| this.ids = ids; | |||
| } | |||
| /*租户ID**/ | |||
| @io.swagger.annotations.ApiModelProperty(value="租户ID",name="tenantId") | |||
| private String tenantId; | |||
| /*模板ID**/ | |||
| @io.swagger.annotations.ApiModelProperty(value="模板ID",name="templateId") | |||
| private String templateId; | |||
| /*模板类型1:支付成功消息2:退款申请成功消息**/ | |||
| @io.swagger.annotations.ApiModelProperty(value="模板类型1:支付成功消息2:退款申请成功消息",name="type") | |||
| private Integer type; | |||
| /*创建时间**/ | |||
| @io.swagger.annotations.ApiModelProperty(value="创建时间",name="createDate") | |||
| private Date createDate; | |||
| /*更新时间**/ | |||
| @io.swagger.annotations.ApiModelProperty(value="更新时间",name="updateDate") | |||
| private Date updateDate; | |||
| public String getTenantId() { | |||
| return tenantId; | |||
| } | |||
| public void setTenantId(String _tenantId) { | |||
| tenantId = _tenantId; | |||
| } | |||
| public String getTemplateId() { | |||
| return templateId; | |||
| } | |||
| public void setTemplateId(String _templateId) { | |||
| templateId = _templateId; | |||
| } | |||
| public Integer getType() { | |||
| return type; | |||
| } | |||
| public void setType(Integer _type) { | |||
| type = _type; | |||
| } | |||
| public Date getCreateDate() { | |||
| return createDate; | |||
| } | |||
| public void setCreateDate(Date _createDate) { | |||
| createDate = _createDate; | |||
| } | |||
| public Date getUpdateDate() { | |||
| return updateDate; | |||
| } | |||
| public void setUpdateDate(Date _updateDate) { | |||
| updateDate = _updateDate; | |||
| } | |||
| public static enum Field | |||
| { | |||
| Id_ASC("`id` ASC"),Id_DESC("`id` DESC") | |||
| ,TenantId_ASC("`tenantId` ASC"),TenantId_DESC("`tenantId` DESC") | |||
| ,TemplateId_ASC("`templateId` ASC"),TemplateId_DESC("`templateId` DESC") | |||
| ,Type_ASC("`type` ASC"),Type_DESC("`type` DESC") | |||
| ,CreateDate_ASC("`createDate` ASC"),CreateDate_DESC("`createDate` DESC") | |||
| ,UpdateDate_ASC("`updateDate` ASC"),UpdateDate_DESC("`updateDate` DESC") | |||
| ; | |||
| private String value; | |||
| Field(String value){ | |||
| this.value = value; | |||
| } | |||
| public String getValue() { | |||
| return value; | |||
| } | |||
| public void setCol(String value) { | |||
| this.value = value; | |||
| } | |||
| @Override | |||
| public String toString() { | |||
| return this.getValue(); | |||
| } | |||
| } | |||
| public void setSortColumns(WxTemplateMsg.Field... fields) | |||
| { | |||
| if (fields == null || fields.length == 0) { | |||
| return; | |||
| } | |||
| for (int k = 0; k < fields.length; k++) { | |||
| if (fields[k] == null) { | |||
| return; | |||
| } | |||
| } | |||
| StringBuilder sb = new StringBuilder(fields[0].toString()); | |||
| for (int k = 1; k < fields.length; k++) { | |||
| sb.append(","); | |||
| sb.append(fields[k].toString()); | |||
| } | |||
| } | |||
| public void setSortColumns(String sortColumns) | |||
| { | |||
| if (sortColumns == null || "".equals(sortColumns.trim())) { | |||
| return; | |||
| } | |||
| if (sortColumns.contains(",")) { | |||
| String[] cols = sortColumns.split(","); | |||
| java.util.List<Field> fList = new java.util.ArrayList(); | |||
| for (int k = 0; k < cols.length; k++) { | |||
| fList.add(Field.valueOf(cols[k])); | |||
| } | |||
| this.setSortColumns(fList.toArray(new Field[fList.size()])); | |||
| } else { | |||
| this.setSortColumns(Field.valueOf(sortColumns)); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,39 @@ | |||
| package com.simple.enums; | |||
| /** | |||
| * Created by Stormeye on 2018/08/09. | |||
| */ | |||
| public enum EnumTemplateType { | |||
| // 1-支付成功消息, 2-支付失败消息 3-退款消息 | |||
| PAY_SUCCESS(1, "订单支付成功通知"), | |||
| PAY_FAIL(2, "支付失败通知"), | |||
| REFUND(3, "退款通知") | |||
| ; | |||
| public static EnumTemplateType getEnum(Integer code) { | |||
| for (EnumTemplateType value : values()) { | |||
| if (value.getCode().equals(code)) { | |||
| return value; | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| private Integer code; | |||
| private String message; | |||
| EnumTemplateType(Integer code, String message) { | |||
| this.code = code; | |||
| this.message = message; | |||
| } | |||
| public Integer getCode() { | |||
| return code; | |||
| } | |||
| public String getMessage() { | |||
| return message; | |||
| } | |||
| } | |||
| @@ -0,0 +1,17 @@ | |||
| package com.simple.mapper; | |||
| import java.util.*; | |||
| import com.simple.common.CommonMapper; | |||
| import org.apache.ibatis.annotations.Param; | |||
| import com.simple.domain.po.WxTemplateMsg; | |||
| public interface WxTemplateMsgMapper extends CommonMapper<WxTemplateMsg, Long> { | |||
| List<WxTemplateMsg> findList(WxTemplateMsg wxTemplateMsg); | |||
| } | |||
| @@ -0,0 +1,48 @@ | |||
| package com.simple.service; | |||
| import java.util.*; | |||
| import com.github.pagehelper.PageInfo; | |||
| import com.simple.domain.po.WxTemplateMsg; | |||
| public interface WxTemplateMsgService { | |||
| /** | |||
| * 根据实体查询分页列表 | |||
| * | |||
| * @param record | |||
| * @param offset | |||
| * @param limit | |||
| * @return | |||
| */ | |||
| PageInfo<WxTemplateMsg> listAsPage(WxTemplateMsg record, Integer pageIndex, Integer pageSize); | |||
| /** | |||
| * 根据Id获得实体 | |||
| * | |||
| * @param id | |||
| * @return | |||
| */ | |||
| WxTemplateMsg getById(Long id); | |||
| /** | |||
| * 保存或更新实体 | |||
| * | |||
| * @param record | |||
| */ | |||
| void saveOrUpdate(WxTemplateMsg record); | |||
| /** | |||
| * 根据Id删除实体 | |||
| * | |||
| * @param id | |||
| */ | |||
| void deleteById(Long id); | |||
| } | |||
| @@ -1,29 +1,28 @@ | |||
| package com.simple.service.impl; | |||
| import java.text.ParseException; | |||
| import java.text.SimpleDateFormat; | |||
| import java.util.*; | |||
| import cn.binarywang.wx.miniapp.api.WxMaService; | |||
| import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.github.pagehelper.PageHelper; | |||
| import com.github.pagehelper.PageInfo; | |||
| import com.google.common.collect.Lists; | |||
| import com.simple.common.ErrorCode; | |||
| import com.simple.common.Result; | |||
| import com.simple.common.ResultData; | |||
| import com.simple.domain.po.*; | |||
| import com.simple.enums.EnumOrderStatus; | |||
| import com.simple.enums.EnumPayStatus; | |||
| import com.simple.enums.EnumPayType; | |||
| import com.simple.enums.EnumPayWay; | |||
| import com.simple.enums.*; | |||
| import com.simple.exception.MallinkException; | |||
| import com.simple.mapper.*; | |||
| import com.simple.pay.*; | |||
| import com.simple.service.WxOrderService; | |||
| import com.simple.service.WxPayOrderService; | |||
| import com.simple.utils.BeanUtils; | |||
| import com.simple.utils.MapUtil; | |||
| import com.simple.utils.Utility; | |||
| import com.simple.utils.XmlUtil; | |||
| import com.simple.utils.*; | |||
| import me.chanjar.weixin.common.error.WxErrorException; | |||
| import org.apache.log4j.Logger; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Service; | |||
| @@ -48,11 +47,21 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { | |||
| @Autowired | |||
| WxOrderMapper wxOrderMapper; | |||
| @Autowired | |||
| WxOrderService wxOrderService; | |||
| @Autowired | |||
| WxCouponMapper wxCouponMapper; | |||
| @Autowired | |||
| WxPayOrderMapper wxPayOrderMapper; | |||
| @Autowired | |||
| WxOrderService wxOrderService; | |||
| WxTemplateMsgMapper wxTemplateMsgMapper; | |||
| @Autowired | |||
| WxMerchantMapper wxMerchantMapper; | |||
| JSONObject errorMap = JSON.parseObject("{" + | |||
| "\"NOAUTH\":{\"detail\":\"商户无此接口权限\",\"reason\":\"商户未开通此接口权限\",\"resolution\":\"请商户前往申请此接口权限\"}," + | |||
| @@ -453,13 +462,10 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { | |||
| logger.error("订单数据库更新失败: " + e.getMessage()); | |||
| throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "订单数据库更新失败: " + e.getMessage()); | |||
| } | |||
| // 创建couponOrder | |||
| try { | |||
| wxOrderService.updateOrderStatus(order, EnumOrderStatus.ORDER_STATUS_PAYMENT_SUCCESS); | |||
| } catch (Exception e) { | |||
| logger.error("订单数据库更新失败: " + e.getMessage()); | |||
| throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "订单数据库更新失败: " + e.getMessage()); | |||
| } | |||
| // 微信模板通知用户 | |||
| //sendPaySuccessMsg(order, updateOrder); | |||
| // End of 微信模板通知用户 | |||
| /* | |||
| Map<String, String> msgMap = new HashMap<>(); | |||
| @@ -476,6 +482,75 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { | |||
| */ | |||
| } | |||
| /** | |||
| * 微信模板通知用户 | |||
| * @param updateOrder | |||
| * 支付时间 {{keyword1.DATA}} | |||
| * 支付方式 {{keyword2.DATA}} | |||
| * 支付金额 {{keyword3.DATA}} | |||
| * 商品名称 {{keyword4.DATA}} | |||
| * 商家名称 {{keyword5.DATA}} | |||
| * 订单状态 {{keyword6.DATA}} | |||
| */ | |||
| private void sendPaySuccessMsg(WxAppinfo appInfo, WxOrder order, WxPayOrder updateOrder) { | |||
| // 1. get template id | |||
| WxTemplateMsg msgQ = new WxTemplateMsg(); | |||
| msgQ.setTenantId(order.getTenantId()); | |||
| msgQ.setType(EnumTemplateType.PAY_SUCCESS.getCode()); | |||
| WxTemplateMsg msg = null; | |||
| List<WxTemplateMsg> list= wxTemplateMsgMapper.select(msgQ); | |||
| if (list.size() > 0) { | |||
| msg = list.get(0); | |||
| } | |||
| if (msg == null) { | |||
| logger.error("找不到模板Id"); | |||
| throw new MallinkException(ErrorCode.TEMPLATE_NOT_FOUND); | |||
| } | |||
| // 2. get coupon info | |||
| WxCoupon coupon = wxCouponMapper.selectByPrimaryKey(order.getCouponId()); | |||
| if (coupon == null) { | |||
| logger.error("找不到券信息"); | |||
| throw new MallinkException(ErrorCode.COUPON_IS_EMPTY); | |||
| } | |||
| // 3. merchant info | |||
| WxMerchant merchant = wxMerchantMapper.selectByPrimaryKey(order.getMerchantId()); | |||
| if (merchant == null) { | |||
| logger.error("找不到商户信息"); | |||
| throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND); | |||
| } | |||
| // 3. get user info | |||
| WxCUser user = wxCUserMapper.selectByPrimaryKey(order.getCUserId()); | |||
| if (user == null) { | |||
| logger.error("找不到C端用户"); | |||
| throw new MallinkException(ErrorCode.USER_IS_EMPTY); | |||
| } | |||
| WxMaService wxMaService = MaUtil.getWeappService(appInfo); | |||
| SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); | |||
| WxMaTemplateMessage templateMessage = WxMaTemplateMessage.builder() | |||
| .toUser(user.getOpenId()) | |||
| .formId("FORMID") | |||
| .page("index") | |||
| .data(Lists.newArrayList( | |||
| new WxMaTemplateMessage.Data("keyword1", dateFormat.format(new Date()), "#173177"), | |||
| new WxMaTemplateMessage.Data("keyword2", "微信支付", "#173177"), | |||
| new WxMaTemplateMessage.Data("keyword3", String.valueOf(updateOrder.getPayAmount()*1.0/100) + "元", "#173177"), | |||
| new WxMaTemplateMessage.Data("keyword4", coupon.getTitle(), "#173177"), | |||
| new WxMaTemplateMessage.Data("keyword5", merchant.getName(), "#173177"), | |||
| new WxMaTemplateMessage.Data("keyword6", EnumOrderStatus.getEnum(order.getOrderStatus()).getMessage(), "#173177"))) | |||
| .templateId(msg.getTemplateId()) | |||
| .emphasisKeyword("keyword1.DATA") | |||
| .build(); | |||
| //templateMessage.addData( new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177")); | |||
| try { | |||
| wxMaService.getMsgService().sendTemplateMsg(templateMessage); | |||
| } catch (WxErrorException e) { | |||
| logger.error("支付通知发送失败: " + e.getMessage()); | |||
| throw new MallinkException(ErrorCode.TEMPLATE_SEND_FAILED); | |||
| } | |||
| } | |||
| @Override | |||
| @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) | |||
| public void handlePayOrderStatusUpdate(WxPayOrder record) { | |||
| @@ -264,6 +264,8 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { | |||
| logger.error("已经核销过的券: couponOrder-" + couponOrderId); | |||
| throw new MallinkException(ErrorCode.COUPON_ORDER_IS_USED); | |||
| } | |||
| // 创建 refund Order | |||
| // 更改 couponOrder 状态 | |||
| Date currentDate = new Date(); | |||
| wxCouponOrder.setCouponOrderStatus(EnumCouponOrderStatus.COUPON_ORDER_INVALID.getCode()); //3退款,券作废 | |||
| @@ -285,7 +287,8 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { | |||
| } | |||
| // 库存回复+1 | |||
| wxOrderService.stockBack(wxOrder); | |||
| // 创建refundOrder | |||
| // 创建 refundOrder | |||
| WxPayOrder payOrderQ = new WxPayOrder(); | |||
| payOrderQ.setTenantId(appInfo.getTenantId()); | |||
| payOrderQ.setCUserId(wxOrder.getCUserId()); | |||
| @@ -0,0 +1,54 @@ | |||
| package com.simple.service.impl; | |||
| import java.util.*; | |||
| import com.github.pagehelper.PageHelper; | |||
| import com.github.pagehelper.PageInfo; | |||
| import com.simple.domain.po.WxTemplateMsg; | |||
| import com.simple.mapper.WxTemplateMsgMapper; | |||
| import com.simple.service.WxTemplateMsgService; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Service; | |||
| import com.simple.common.IdWorker; | |||
| @Service | |||
| public class WxTemplateMsgServiceImpl implements WxTemplateMsgService { | |||
| @Autowired | |||
| WxTemplateMsgMapper wxTemplateMsgMapper; | |||
| @Override | |||
| public PageInfo<WxTemplateMsg> listAsPage(WxTemplateMsg record, Integer pageIndex, Integer pageSize) { | |||
| return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxTemplateMsgMapper.findList(record)); | |||
| } | |||
| @Override | |||
| public WxTemplateMsg getById(Long id) { | |||
| return wxTemplateMsgMapper.selectByPrimaryKey(id); | |||
| } | |||
| @Override | |||
| public void saveOrUpdate(WxTemplateMsg record) { | |||
| if (record.getId() == null) { | |||
| //record.setId(UUID.randomUUID().toString().replaceAll("-", "")); | |||
| final IdWorker idWorker = IdWorker.get(); | |||
| record.setId(idWorker.nextId()); | |||
| wxTemplateMsgMapper.insertSelective(record); | |||
| } else { | |||
| wxTemplateMsgMapper.updateByPrimaryKeySelective(record); | |||
| } | |||
| } | |||
| @Override | |||
| public void deleteById(Long id) { | |||
| wxTemplateMsgMapper.deleteByPrimaryKey(id); | |||
| } | |||
| } | |||
| @@ -0,0 +1,22 @@ | |||
| package com.simple.utils; | |||
| import cn.binarywang.wx.miniapp.api.WxMaService; | |||
| import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; | |||
| import cn.binarywang.wx.miniapp.config.WxMaInMemoryConfig; | |||
| import com.simple.domain.po.WxAppinfo; | |||
| public class MaUtil { | |||
| static public WxMaService getWeappService(WxAppinfo appinfo) { | |||
| WxMaInMemoryConfig config = new WxMaInMemoryConfig(); | |||
| config.setAppid(appinfo.getAppId()); | |||
| config.setSecret(appinfo.getSecret()); | |||
| config.setToken(appinfo.getToken()); | |||
| config.setAesKey(appinfo.getAesKey()); | |||
| config.setMsgDataFormat(appinfo.getMsgDataFormat()); | |||
| WxMaService service = new WxMaServiceImpl(); | |||
| service.setWxMaConfig(config); | |||
| return service; | |||
| } | |||
| } | |||
| @@ -0,0 +1,68 @@ | |||
| <?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.simple.mapper.WxTemplateMsgMapper"> | |||
| <resultMap id="BaseResultMap" type="com.simple.domain.po.WxTemplateMsg"> | |||
| <id column="id" jdbcType="BIGINT" property="id" /> | |||
| <result column="tenant_id" jdbcType="VARCHAR" property="tenantId" /> | |||
| <result column="template_id" jdbcType="VARCHAR" property="templateId" /> | |||
| <result column="type" jdbcType="INTEGER" property="type" /> | |||
| <result column="create_date" jdbcType="TIMESTAMP" property="createDate" /> | |||
| <result column="update_date" jdbcType="TIMESTAMP" property="updateDate" /> | |||
| </resultMap> | |||
| <sql id="allColumns"> | |||
| `id`,`tenant_id`,`template_id`,`type`,`create_date`,`update_date` | |||
| </sql> | |||
| <sql id="dynamicWhereConditions"> | |||
| where 1 = 1 | |||
| <if test=" null != id "> | |||
| and `id` = #{id} | |||
| </if> | |||
| <if test=" null != tenantId "> | |||
| and `tenant_id` like concat('%', #{tenantId},'%') | |||
| </if> | |||
| <if test=" null != templateId "> | |||
| and `template_id` like concat('%', #{templateId},'%') | |||
| </if> | |||
| <if test=" null != type "> | |||
| and `type` = #{type} | |||
| </if> | |||
| <if test=" null != createDate "> | |||
| and `create_date` = #{createDate} | |||
| </if> | |||
| <if test=" null != updateDate "> | |||
| and `update_date` = #{updateDate} | |||
| </if> | |||
| <if test=" null != ids "> | |||
| and id in | |||
| <foreach collection="ids" index="index" item="idItem" open="(" separator="," close=")"> | |||
| #{idItem} | |||
| </foreach> | |||
| </if> | |||
| <if test=" null != sortColumns"> order by ${sortColumns} </if> | |||
| </sql> | |||
| <select id="findList" parameterType="com.simple.domain.po.WxTemplateMsg" resultMap="BaseResultMap"> | |||
| select <include refid="allColumns" /> from wx_template_msg | |||
| <include refid="dynamicWhereConditions" /> | |||
| </select> | |||
| </mapper> | |||