Selaa lähdekoodia

Merge branch 'dev' of 113.31.163.91:quanshu/mp-server into dev

dai xiaodan 3 vuotta sitten
vanhempi
commit
5dd776b1f7
35 muutettua tiedostoa jossa 1120 lisäystä ja 202 poistoa
  1. 3 0
      mp-admin/src/main/java/com/qs/mp/web/controller/BaseController.java
  2. 6 25
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/ChannelMgrController.java
  3. 10 50
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/SaleSiteMgrController.java
  4. 11 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/callback/PayCallBackController.java
  5. 187 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/ChannelMyTicketController.java
  6. 17 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserMineController.java
  7. 11 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserTicketOrderController.java
  8. 1 1
      mp-common/src/main/java/com/qs/mp/common/enums/TicketPkgSaleStatusEnum.java
  9. 1 1
      mp-common/src/main/java/com/qs/mp/common/pulsar/PulsarClientService.java
  10. 1 1
      mp-quartz/src/main/java/com/qs/mp/quartz/task/ChannelOrderTask.java
  11. 58 0
      mp-quartz/src/main/java/com/qs/mp/quartz/task/OperateToolTask.java
  12. 1 1
      mp-quartz/src/main/java/com/qs/mp/quartz/task/UserDeliverOrderTask.java
  13. 33 0
      mp-service/src/main/java/com/qs/mp/channel/domain/Channel.java
  14. 79 0
      mp-service/src/main/java/com/qs/mp/channel/domain/ChannelTicketTransfer.java
  15. 27 0
      mp-service/src/main/java/com/qs/mp/channel/domain/param/ChannelMyTicketQueryParam.java
  16. 29 0
      mp-service/src/main/java/com/qs/mp/channel/domain/param/ChannelTicketTransferParam.java
  17. 60 0
      mp-service/src/main/java/com/qs/mp/channel/domain/vo/ChannelMyTicketVO.java
  18. 32 0
      mp-service/src/main/java/com/qs/mp/channel/domain/vo/ChannelTicketTransferDetailVO.java
  19. 18 10
      mp-service/src/main/java/com/qs/mp/channel/mapper/ChannelMapper.java
  20. 16 0
      mp-service/src/main/java/com/qs/mp/channel/mapper/ChannelOrderDetailMapper.java
  21. 34 0
      mp-service/src/main/java/com/qs/mp/channel/mapper/ChannelTicketTransferMapper.java
  22. 11 0
      mp-service/src/main/java/com/qs/mp/channel/service/IChannelOrderDetailService.java
  23. 20 4
      mp-service/src/main/java/com/qs/mp/channel/service/IChannelService.java
  24. 44 0
      mp-service/src/main/java/com/qs/mp/channel/service/IChannelTicketTransferService.java
  25. 26 0
      mp-service/src/main/java/com/qs/mp/channel/service/impl/ChannelOrderDetailServiceImpl.java
  26. 20 4
      mp-service/src/main/java/com/qs/mp/channel/service/impl/ChannelServiceImpl.java
  27. 76 0
      mp-service/src/main/java/com/qs/mp/channel/service/impl/ChannelTicketTransferServiceImpl.java
  28. 2 1
      mp-service/src/main/java/com/qs/mp/framework/redis/RedisKey.java
  29. 46 0
      mp-service/src/main/java/com/qs/mp/mq/impl/PulsarConsumerImpl.java
  30. 6 0
      mp-service/src/main/java/com/qs/mp/pay/service/IWalletService.java
  31. 34 10
      mp-service/src/main/java/com/qs/mp/pay/service/impl/WalletServiceImpl.java
  32. 79 85
      mp-service/src/main/java/com/qs/mp/user/service/impl/UserTicketOrderServiceImpl.java
  33. 49 9
      mp-service/src/main/resources/mapper/channel/ChannelMapper.xml
  34. 19 0
      mp-service/src/main/resources/mapper/channel/ChannelOrderDetailMapper.xml
  35. 53 0
      mp-service/src/main/resources/mapper/channel/ChannelTicketTransferMapper.xml

+ 3 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/BaseController.java

@@ -2,14 +2,17 @@ package com.qs.mp.web.controller;
 
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
+import com.qs.mp.common.constant.HttpStatus;
 import com.qs.mp.common.core.domain.AjaxResult;
 import com.qs.mp.common.core.page.PageDomain;
 import com.qs.mp.common.core.page.TableDataInfo;
 import com.qs.mp.common.core.page.TableSupport;
 import com.qs.mp.common.enums.ErrorCodeEnum;
 import com.qs.mp.common.utils.DateUtils;
+import com.qs.mp.utils.SecurityUtils;
 import com.qs.mp.common.utils.StringUtils;
 import com.qs.mp.common.utils.sql.SqlUtil;
+import com.qs.mp.core.domain.LoginUser;
 import java.beans.PropertyEditorSupport;
 import java.util.Date;
 import java.util.List;

+ 6 - 25
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/ChannelMgrController.java

@@ -59,7 +59,7 @@ public class ChannelMgrController extends BaseApiController {
 
 	@Autowired
 	private IChannelOrderService channelOrderService;
-	
+
 	@Autowired
 	private IUserTicketOrderService userTicketOrderService;
 
@@ -144,26 +144,7 @@ public class ChannelMgrController extends BaseApiController {
 		queryWrapper.eq(null != channel && null != channel.getProvinceId(), "t1.province_id", channel.getProvinceId());
 		queryWrapper.eq(null != channel && null != channel.getCityId(), "t1.city_id", channel.getCityId());
 		queryWrapper.eq(null != channel && null != channel.getAreaId(), "t1.area_id", channel.getAreaId());
-		queryWrapper.orderByAsc("t1.level").orderByDesc("t1.channel_id");
-		list = channelService.selectChannelVoList(queryWrapper);
-		if(null != list && list.size() > 0) {
-			for(ChannelVO channelVO : list) {
-				if(null != channelVO && StringUtils.isNotBlank(channelVO.getChannelNo())) {
-					int siteCnt = channelService.getChannelSiteCnt(channelVO.getChannelNo());
-					int userCnt = channelUserRelService.getChannelTotalUserCnt(channelVO.getChannelNo());
-					channelVO.setSiteCnt(siteCnt);
-					channelVO.setUserCnt(userCnt);
-					// 查询用户信息
-					// SysUser sysUser = userService.selectUserById(channelVO.getUserId());
-					// channelVO.setSysUser(sysUser);
-					// 查询子渠道数量
-					int childCnt = channelService.count(
-							new LambdaQueryWrapper<Channel>().eq(Channel::getParentId, channelVO.getChannelId())
-							.gt(Channel::getLevel, 0));
-					channelVO.setChildCnt(childCnt);
- 				}
-			}
-		}
+		list = channelService.selectChannelList(queryWrapper);
 		return getDataTable(list);
 	}
 
@@ -256,7 +237,7 @@ public class ChannelMgrController extends BaseApiController {
 		}
 		boolean mobileChange = false;  // 手机号码是否有变更
 		if(!channel.getMobile().equals(oldChannel.getMobile())) {
-			
+
 			int mobileCount = channelService.count(
 			        new LambdaQueryWrapper<Channel>().eq(Channel::getMobile, channel.getMobile()));
 			if(mobileCount > 0) {
@@ -355,15 +336,15 @@ public class ChannelMgrController extends BaseApiController {
 		//queryWrapper.eq(ChannelOrder::getChannelId, channelId);
 		//int orderCnt = channelOrderService.count(queryWrapper);
 		//channelOperDataVO.setOrderCnt(orderCnt);
-		
+
 		// 盲票销量
 		int ticketSaleCnt = userTicketOrderService.getChannelTotalTicketNumCnt(channelVO.getChannelNo());
 		channelOperDataVO.setTicketSaleCnt(ticketSaleCnt);
 	    channelVO.setOperData(channelOperDataVO);
 		return AjaxResult.success(channelVO);
 	}
-	
-	
+
+
 	// 获取上级渠道迭代
 	private String getParentsName(String channelNo) {
 		if(StringUtils.isNotBlank(channelNo)) {

+ 10 - 50
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/SaleSiteMgrController.java

@@ -68,13 +68,13 @@ public class SaleSiteMgrController extends BaseApiController {
 
 	@Autowired
 	private IChannelOrderService channelOrderService;
-	
+
 	@Autowired
 	private IUserTicketOrderService userTicketOrderService;
 
 	@Autowired
 	private ISysUserService userService;
-	
+
 	@Autowired
 	private ITicketService ticketService;
 
@@ -102,30 +102,8 @@ public class SaleSiteMgrController extends BaseApiController {
 		queryWrapper.eq(null != channel && null != channel.getProvinceId(), "t1.province_id", channel.getProvinceId());
 		queryWrapper.eq(null != channel && null != channel.getCityId(), "t1.city_id", channel.getCityId());
 		queryWrapper.eq(null != channel && null != channel.getAreaId(), "t1.area_id", channel.getAreaId());
-		queryWrapper.orderByDesc("t1.channel_id");
-		list = channelService.selectChannelVoList(queryWrapper);
-		List<Long> channelIds = new ArrayList<Long>();
-		if(null != list && list.size() > 0) {
-			for(ChannelVO channelVO : list) {
-				if(null != channelVO && null != channelVO.getChannelId()
-						&& StringUtils.isNotBlank(channelVO.getChannelNo())) {
-					channelIds.add(channelVO.getChannelId());
- 				}
-			}
-		}
-		List<TicketCntVO>  qtyCntList = new ArrayList<TicketCntVO>();
-		List<TicketCntVO>  saleCntList = new ArrayList<TicketCntVO>();
-		if(null != channelIds && channelIds.size() > 0) {
-			QueryWrapper<ChannelOrderDetail> ticketQtyCntQueryWrapper = new QueryWrapper<ChannelOrderDetail>();
-			ticketQtyCntQueryWrapper.in("t1.channel_id", channelIds);
-			qtyCntList = ticketService.listTicketQtyCnt(ticketQtyCntQueryWrapper);
-			
-	    	QueryWrapper<UserTicketOrder> ticketSaleCntQueryWrapper = new QueryWrapper<UserTicketOrder>();
-	    	ticketSaleCntQueryWrapper.in("t1.channel_id", channelIds);
-	    	ticketSaleCntQueryWrapper.eq("t1.`status`", 1);
-	    	saleCntList = userTicketOrderService.listTicketSaleCnt(ticketSaleCntQueryWrapper);
-		}
-		
+		list = channelService.selectSaleSiteList(queryWrapper);
+
 		if(null != list && list.size() > 0) {
 			for(ChannelVO channelVO : list) {
 				if(null != channelVO && null != channelVO.getChannelId()
@@ -139,30 +117,12 @@ public class SaleSiteMgrController extends BaseApiController {
 					//SysUser sysUser = userService.selectUserById(channelVO.getUserId());
 					// channelVO.setSysUser(sysUser);
 					channelVO.setParentsName(getParentsName(channelVO.getChannelNo()));
-					// 统计盲票库存, 销量
-					if(null != qtyCntList && qtyCntList.size() > 0) {
-						List<TicketCntVO> voList =  qtyCntList.stream().filter(item  -> item.getChannelId().equals(channelVO.getChannelId()))
-				                .collect(Collectors.toList());
-						if(null != voList && voList.size() > 0) {
-							TicketCntVO ticketQtyCnt =  voList.get(0);
-							channelVO.setOffLineQtyCnt(null != ticketQtyCnt?ticketQtyCnt.getOffLineQtyCnt():0);
-						}
-					}
-					if(null != saleCntList && saleCntList.size() > 0) {
-						List<TicketCntVO> voList =  saleCntList.stream().filter(item  -> item.getChannelId().equals(channelVO.getChannelId()))
-				                .collect(Collectors.toList());
-						if(null != voList && voList.size() > 0) {
-							TicketCntVO ticketSaleCnt =  voList.get(0);
-							channelVO.setOffLineSaleCnt(null != ticketSaleCnt?ticketSaleCnt.getOffLineSaleCnt():0);
-							channelVO.setOnLineSaleCnt(null != ticketSaleCnt?ticketSaleCnt.getOnLineSaleCnt():0);
-						}
-					}
  				}
 			}
 		}
 		return getDataTable(list);
 	}
-	
+
 	// 获取上级渠道迭代
 	private String getParentsName(String channelNo) {
 		if(StringUtils.isNotBlank(channelNo)) {
@@ -388,26 +348,26 @@ public class SaleSiteMgrController extends BaseApiController {
 		}
 	    // 查询经销商销售额、佣金收入、订单数等
 	    ChannelOperDataVO channelOperDataVO = channelService.getChannelTotalOperData(channelVO.getChannelNo());
-		
+
 		// 盲票销售张数
 		int ticketSaleCnt = userTicketOrderService.getSaleSiteTotalTicketNumCnt(channelVO.getChannelId());
 		channelOperDataVO.setTicketSaleCnt(ticketSaleCnt);
 	    channelVO.setOperData(channelOperDataVO);
-	    
+
         if(null != channelVO && null != channelVO.getChannelId()) {
 	    	LambdaQueryWrapper<ChannelUserRel> userCntQueryWrapper = new LambdaQueryWrapper<ChannelUserRel>();
 			userCntQueryWrapper.eq(ChannelUserRel::getChannelId, channelVO.getChannelId());
 			int userCnt = channelUserRelService.count(userCntQueryWrapper);
 			channelVO.setUserCnt(userCnt);
-	    	
+
 	    	int ticketQtyCnt = ticketService.getTicketQtyCnt(channelVO.getChannelId());
 	    	channelVO.setOffLineQtyCnt(ticketQtyCnt);
-	    	
+
 	    	TicketCntVO ticketCnt = userTicketOrderService.getTicketSaleCnt(channelVO.getChannelId());
 			channelVO.setOffLineSaleCnt(null != ticketCnt?ticketCnt.getOffLineSaleCnt():0);
 			channelVO.setOnLineSaleCnt(null != ticketCnt?ticketCnt.getOnLineSaleCnt():0);
 	    }
-	    
+
 		return AjaxResult.success(channelVO);
 	}
 

+ 11 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/callback/PayCallBackController.java

@@ -1,6 +1,8 @@
 package com.qs.mp.web.controller.api.callback;
 
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.qs.mp.common.enums.PayOrderStatusEnum;
+import com.qs.mp.common.exception.ServiceException;
 import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.common.utils.StringUtils;
 import com.qs.mp.common.utils.WebhookService;
@@ -79,6 +81,15 @@ public class PayCallBackController {
     payOrder.setOrderStatus(orderStatus);
 
     try {
+      // 订单支付状态单独保存
+      LambdaUpdateWrapper<PayOrder> updateWrapper = new LambdaUpdateWrapper<>();
+      updateWrapper.eq(PayOrder::getOrderStatus, PayOrderStatusEnum.WAIT.getValue());
+      updateWrapper.eq(PayOrder::getOrderId, shopOrderNo);
+      boolean ret = payOrderService.update(payOrder, updateWrapper);
+      if (!ret) {
+        throw new ServiceException("支付订单更新失败,orderId:" + shopOrderNo);
+      }
+
       // 更新订单,单个事务处理
       logger.info("支付回调消息更新成功 shopOrderNo:"+shopOrderNo);
       walletService.payOrderStatusHandle(payOrder);

+ 187 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/ChannelMyTicketController.java

@@ -0,0 +1,187 @@
+package com.qs.mp.web.controller.api.channel;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.qs.mp.admin.domain.TicketPackage;
+import com.qs.mp.admin.service.ITicketPackageService;
+import com.qs.mp.channel.domain.Channel;
+import com.qs.mp.channel.domain.ChannelOrderDetail;
+import com.qs.mp.channel.domain.ChannelTicketTransfer;
+import com.qs.mp.channel.domain.param.ChannelMyTicketQueryParam;
+import com.qs.mp.channel.domain.param.ChannelTicketTransferParam;
+import com.qs.mp.channel.domain.vo.ChannelMyTicketVO;
+import com.qs.mp.channel.domain.vo.ChannelTicketTransferDetailVO;
+import com.qs.mp.channel.service.IChannelOrderDetailService;
+import com.qs.mp.channel.service.IChannelService;
+import com.qs.mp.channel.service.IChannelTicketTransferService;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.enums.ChannelCertifyStatusEnum;
+import com.qs.mp.common.enums.TicketPkgSaleStatusEnum;
+import com.qs.mp.common.utils.StringUtils;
+import com.qs.mp.utils.SecurityUtils;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 我的盲票相关接口
+ * @author Cup
+ * @date 2022/4/21
+ */
+@RestController
+@RequestMapping("/api/v1/mp/channel/my/ticket")
+@Api(tags = "我的盲票相关接口")
+public class ChannelMyTicketController extends BaseApiController {
+
+    @Autowired
+    private IChannelOrderDetailService channelOrderDetailService;
+
+    @Autowired
+    private IChannelService channelService;
+
+    @Autowired
+    private IChannelTicketTransferService channelTicketTransferService;
+
+    @Autowired
+    private ITicketPackageService ticketPackageService;
+
+    @PostMapping("list")
+    @ApiOperation("我的盲票列表")
+    @ApiResponses(
+            @ApiResponse(code = 200, message = "成功", response = ChannelMyTicketVO.class)
+    )
+    public TableDataInfo list(@RequestBody ChannelMyTicketQueryParam channelMyTicketQueryParam) {
+        Long channelId = SecurityUtils.getLoginUser().getChannelId();
+        if (channelId == null) {
+            throw new RuntimeException("非法调用");
+        }
+
+        startPage();
+        // 获取我的盲票列表
+        List<ChannelMyTicketVO> list =  channelOrderDetailService.listMyTicket(channelId, channelMyTicketQueryParam);
+        return getDataTable(list);
+    }
+
+    @PostMapping("/channel/mobile/{mobile}")
+    @ApiOperation("根据手机号获取经销商信息")
+    @ApiImplicitParams(
+            @ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String", paramType = "path")
+    )
+    @ApiResponses(
+            @ApiResponse(code = 200, message = "成功", response = Channel.class)
+    )
+    public AjaxResult channelInfoByMobile(@PathVariable("mobile") String mobile) {
+        Long channelId = SecurityUtils.getLoginUser().getChannelId();
+        if (channelId == null) {
+            return AjaxResult.error("非法调用");
+        }
+        if (StringUtils.isBlank(mobile)) {
+            return AjaxResult.success();
+        }
+        Channel channel = channelService.getOne(new LambdaQueryWrapper<Channel>()
+                .eq(Channel::getMobile, mobile)
+                .eq(Channel::getLevel, 0));
+
+        return AjaxResult.success(channel);
+    }
+
+
+
+
+    @PostMapping("/transfer/save")
+    @ApiOperation("盲票转让")
+    public AjaxResult transfer(@RequestBody ChannelTicketTransferParam channelTicketTransferParam) {
+        // 自己为转让人
+        Long transferChannelId = SecurityUtils.getLoginUser().getChannelId();
+        if (transferChannelId == null) {
+            return AjaxResult.error("非法调用");
+        }
+        if (StringUtils.isBlank(channelTicketTransferParam.getBoxId()) ||
+                StringUtils.isBlank(channelTicketTransferParam.getPkgId()) ||
+                Objects.isNull(channelTicketTransferParam.getChannelId()) ||
+                StringUtils.isBlank(channelTicketTransferParam.getMobile())) {
+            return AjaxResult.error("转让参数不能为空");
+        }
+
+        // 校验受让人信息
+        Channel channel = channelService.getOne(new LambdaQueryWrapper<Channel>()
+                .eq(Channel::getChannelId, channelTicketTransferParam.getChannelId())
+                .eq(Channel::getLevel, 0));
+        if (Objects.isNull(channel)) {
+            return AjaxResult.error("受让人信息不存在");
+        }
+        if (ChannelCertifyStatusEnum.NOT_CERTIFIED.equals(channel.getCertifyStatus())) {
+            return AjaxResult.error("受让门店未认证");
+        }
+        if (transferChannelId.equals(channel.getChannelId())) {
+            return AjaxResult.error("不能转让给自己");
+        }
+
+        // 校验当前操作的盲票是否为自己的盲票
+        int count = channelOrderDetailService.count(new LambdaQueryWrapper<ChannelOrderDetail>()
+                .eq(ChannelOrderDetail::getChannelId, transferChannelId)
+                .eq(ChannelOrderDetail::getPkgId, channelTicketTransferParam.getPkgId()));
+        if (count == 0) {
+            return AjaxResult.error("非法操作他人盲票");
+        }
+        // 校验票包是否为待售状态
+        count = ticketPackageService.count(new LambdaQueryWrapper<TicketPackage>().eq(TicketPackage::getPkgId, channelTicketTransferParam.getPkgId())
+                .eq(TicketPackage::getSaleStatus, TicketPkgSaleStatusEnum.WAIT_SALE));
+        if (count == 0) {
+            return AjaxResult.error("票包不为待售状态");
+        }
+
+        // 转让盲票
+        boolean flag  = channelTicketTransferService.transferTicket(transferChannelId, channelTicketTransferParam);
+
+        return AjaxResult.success(flag);
+
+    }
+
+
+
+    @PostMapping("/transfer/list")
+    @ApiOperation("已转让盲票列表")
+    @ApiResponses(
+            @ApiResponse(code = 200, message = "成功", response = ChannelMyTicketVO.class)
+    )
+    public TableDataInfo transferList(){
+        Long transferChannelId = SecurityUtils.getLoginUser().getChannelId();
+        if (transferChannelId == null) {
+            throw new RuntimeException("非法调用");
+        }
+
+        // 开启分页
+        startPage();
+
+        // 获取我的已转让的盲票列表
+        List<ChannelMyTicketVO> list = channelTicketTransferService.listTransferTicketList(transferChannelId);
+        return getDataTable(list);
+    }
+
+
+    @PostMapping("/transfer/detail/{id}")
+    @ApiOperation("转让盲票详情")
+    @ApiImplicitParams(
+            @ApiImplicitParam(name = "id", value = "转让详情id", required = true, dataType = "Long", paramType = "query")
+    )
+    @ApiResponses(
+            @ApiResponse(code = 200, message = "成功", response = ChannelTicketTransferDetailVO.class)
+    )
+    public AjaxResult detail(@PathVariable("id") Long id) {
+        Long transferChannelId = SecurityUtils.getLoginUser().getChannelId();
+
+        if (transferChannelId == null) {
+            return AjaxResult.error("非法调用");
+        }
+
+        ChannelTicketTransferDetailVO channelTicketTransferDetailVO =  channelTicketTransferService.getTicketTransferDetailById(id, transferChannelId);
+
+        return AjaxResult.success(channelTicketTransferDetailVO);
+    }
+
+}

+ 17 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserMineController.java

@@ -35,6 +35,7 @@ import io.swagger.annotations.ApiResponses;
 import lombok.AllArgsConstructor;
 import ma.glasnost.orika.MapperFacade;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -108,6 +109,22 @@ public class UserMineController extends BaseApiController {
     return getDataTable(userCouponVOList);
   }
 
+  /**
+   * 优惠券详情
+   */
+  @PostMapping("/coupon/detail")
+  @ApiOperation(value = "优惠券详情", notes = "获取我的优惠券详情")
+  public AjaxResult getCouponInfo(@RequestBody UserCoupon param) {
+    Long userId = SecurityUtils.getLoginUser().getUserId();
+    List<UserCouponVO> userCouponVOList = userCouponService.listUserCouponVO(new QueryWrapper<UserCoupon>()
+        .eq("t1.id", param.getId())
+        .eq("t1.user_id", userId));
+    if (!CollectionUtils.isEmpty(userCouponVOList)) {
+      return AjaxResult.success(userCouponVOList.get(0));
+    }
+    return AjaxResult.error("优惠券不存在");
+  }
+
   /**
    * 我的盲豆
    */

+ 11 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserTicketOrderController.java

@@ -15,8 +15,10 @@ import com.qs.mp.common.core.redis.RedisCache;
 import com.qs.mp.common.enums.BizTypeEnum;
 import com.qs.mp.common.enums.CouponUseAreaEnum;
 import com.qs.mp.common.enums.ErrorCodeEnum;
+import com.qs.mp.common.enums.MqTopicType;
 import com.qs.mp.common.enums.TicketTypeEnum;
 import com.qs.mp.common.exception.ServiceException;
+import com.qs.mp.common.pulsar.PulsarClientService;
 import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.common.utils.StringUtils;
 import com.qs.mp.framework.redis.RedisKey;
@@ -41,6 +43,7 @@ import java.util.concurrent.TimeUnit;
 import javax.validation.Valid;
 import lombok.AllArgsConstructor;
 import ma.glasnost.orika.MapperFacade;
+import org.apache.pulsar.client.api.PulsarClientException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -80,6 +83,9 @@ public class UserTicketOrderController extends BaseApiController {
   @Autowired
   private RedisCache redisCache;
 
+  @Autowired
+  private PulsarClientService pulsarClientService;
+
 
   /**
    * 订单结算,每次更换优惠券时需重新请求此接口
@@ -159,6 +165,11 @@ public class UserTicketOrderController extends BaseApiController {
       jsonObject.put("needPay", 1);
     } else {
       jsonObject.put("needPay", 0);
+      try {
+          pulsarClientService.producer(MqTopicType.ticket_pay, orderId);
+      } catch (PulsarClientException e) {
+        LogUtil.error(logger, e, "盲票支付成功,发送异步消息失败. orderId:{0}", orderId);
+      }
     }
     // 清除缓存的订单
     redisCache.deleteObject(RedisKey.build(RedisKey.USER_TICKET_ORDER_KEY, userId));

+ 1 - 1
mp-common/src/main/java/com/qs/mp/common/enums/TicketPkgSaleStatusEnum.java

@@ -15,7 +15,7 @@ public enum TicketPkgSaleStatusEnum implements IEnum<Integer> {
 
   WAIT_SALE(1, "待售"),
   ON_SALE(2, "销售中"),
-  SALE_OUT(3, "已售");
+  SALE_OUT(3, "已售");
 
   private final Integer value;
   private final String desc;

+ 1 - 1
mp-common/src/main/java/com/qs/mp/common/pulsar/PulsarClientService.java

@@ -143,7 +143,7 @@ public class PulsarClientService {
     Producer<byte[]> finalProducer = producer;
     messageIdFuture.whenComplete(((messageId, throwable) -> {
       if (null != throwable) {
-        logger.error("【消息投递异常,开始重试】", throwable);
+        logger.error("【消息投递异常,开始重试】mq data:" + data, throwable);
         //todo 失败重试策略
         try {
           finalProducer.newMessage().deliverAfter(5, TimeUnit.SECONDS

+ 1 - 1
mp-quartz/src/main/java/com/qs/mp/quartz/task/ChannelOrderTask.java

@@ -40,7 +40,7 @@ public class ChannelOrderTask {
   /**
    * x天前的待收货订单自动确认收货任务
    */
-  public void confirm(int day) {
+  public void confirm(Integer day) {
     LogUtil.info(logger, "...渠道商订单自动确认收货任务开始...");
     LocalDateTime now = LocalDateTimeUtil.now();
     LocalDateTime deliveryTime = LocalDateTimeUtil.offset(now, -day, ChronoUnit.DAYS);

+ 58 - 0
mp-quartz/src/main/java/com/qs/mp/quartz/task/OperateToolTask.java

@@ -0,0 +1,58 @@
+package com.qs.mp.quartz.task;
+
+import com.qs.mp.common.enums.MqTopicType;
+import com.qs.mp.common.pulsar.PulsarClientService;
+import com.qs.mp.common.utils.LogUtil;
+import com.qs.mp.pay.service.IWalletService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 后台人工操作入口
+ *
+ * @author zhongcp
+ * @Date 2022/3/17
+ */
+@Component("operateToolTask")
+public class OperateToolTask {
+
+  protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
+
+  @Autowired
+  private PulsarClientService pulsarClientService;
+
+  @Autowired
+  private IWalletService walletService;
+
+  /**
+   * 重新发送消息
+   */
+  public void resendTicketPayMsg(String orderId) {
+    LogUtil.info(logger, "...重新发送盲票支付消息任务开始...");
+
+    try {
+      pulsarClientService.producer(MqTopicType.ticket_pay, orderId);
+    } catch (Exception e) {
+      LogUtil.error(logger, e, "重新发送盲票支付消息异常。orderId:{0}", orderId);
+    }
+
+    LogUtil.info(logger, "...重新发送盲票支付消息任务结束...");
+  }
+
+
+  /**
+   * 退款
+   * @param orderNo
+   * @param refundAmount
+   */
+  public void refund(String orderNo, Integer refundAmount){
+    LogUtil.info(logger, "...退款任务开始...");
+
+    walletService.refund(orderNo, refundAmount);
+
+    LogUtil.info(logger, "...退款任务结束...");
+
+  }
+}

+ 1 - 1
mp-quartz/src/main/java/com/qs/mp/quartz/task/UserDeliverOrderTask.java

@@ -38,7 +38,7 @@ public class UserDeliverOrderTask {
     /**
      * x天前的待收货订单自动确认收货任务
      */
-    public void confirm(int day) {
+    public void confirm(Integer day) {
         LogUtil.info(logger, "...用户提货订单自动确认收货任务开始...");
         LocalDateTime now = LocalDateTimeUtil.now();
         LocalDateTime deliveryTime = LocalDateTimeUtil.offset(now, -day, ChronoUnit.DAYS);

+ 33 - 0
mp-service/src/main/java/com/qs/mp/channel/domain/Channel.java

@@ -13,6 +13,9 @@ import com.qs.mp.common.enums.SiteTypeEnum;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.Date;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 /**
@@ -22,6 +25,7 @@ import lombok.Data;
  */
 @TableName("mp_channel")
 @Data
+@ApiModel("渠道经销商实体类")
 public class Channel implements Serializable {
 
   private static final long serialVersionUID = 1L;
@@ -30,30 +34,35 @@ public class Channel implements Serializable {
    * 主键
    */
   @TableId(value = "channel_id" , type = IdType.AUTO)
+  @ApiModelProperty("渠道经销商id")
   private Long channelId;
 
   /**
    * 渠道编码
    */
   @TableField("channel_no")
+  @ApiModelProperty("渠道编码")
   private String channelNo;
 
   /**
    * 渠道名称
    */
   @TableField("name")
+  @ApiModelProperty("渠道名称")
   private String name;
 
   /**
    * 父渠道ID
    */
   @TableField("parent_id")
+  @ApiModelProperty("父渠道ID")
   private Long parentId;
 
   /**
    * 渠道级别,0:经销商;1:一级渠道;2:二级渠道
    */
   @TableField("level")
+  @ApiModelProperty("渠道级别,0:经销商;1:一级渠道;2:二级渠道")
   private Integer level;
 
   /**
@@ -61,6 +70,7 @@ public class Channel implements Serializable {
    */
   @TableField("site_type")
   @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
+  @ApiModelProperty("经销商类型")
   private SiteTypeEnum siteType;
   
   
@@ -68,84 +78,98 @@ public class Channel implements Serializable {
    * 门店名称(用于用户端优惠券的详情页,说明优惠券的适用门店)
    */
   @TableField("site_name")
+  @ApiModelProperty("门店名称(用于用户端优惠券的详情页,说明优惠券的适用门店)")
   private String siteName;
 
   /**
    * 分佣百分比
    */
   @TableField("comm_rate")
+  @ApiModelProperty("分佣百分比")
   private BigDecimal commRate;
 
   /**
    * 省ID
    */
   @TableField("province_id")
+  @ApiModelProperty("省ID")
   private Long provinceId;
 
   /**
    * 省
    */
   @TableField("province")
+  @ApiModelProperty("省")
   private String province;
 
   /**
    * 城市
    */
   @TableField("city")
+  @ApiModelProperty("城市")
   private String city;
 
   /**
    * 城市ID
    */
   @TableField("city_id")
+  @ApiModelProperty("城市ID")
   private Long cityId;
 
   /**
    * 区
    */
   @TableField("area")
+  @ApiModelProperty("区")
   private String area;
 
   /**
    * 区ID
    */
   @TableField("area_id")
+  @ApiModelProperty("区ID")
   private Long areaId;
 
   /**
    * 详细地址
    */
   @TableField("address")
+  @ApiModelProperty("详细地址")
   private String address;
 
   /**
    * 联系人
    */
   @TableField("contact")
+  @ApiModelProperty("联系人")
   private String contact;
 
   /**
    * 手机号
    */
   @TableField("mobile")
+  @ApiModelProperty("手机号")
   private String mobile;
 
   /**
    * 用户ID
    */
   @TableField("user_id")
+  @ApiModelProperty("用户ID")
   private Long userId;
 
   /**
    * 账户余额
    */
   @TableField("money")
+  @ApiModelProperty("账户余额")
   private Integer money;
 
   /**
    * 账户冻结金额
    */
   @TableField("frozen_money")
+  @ApiModelProperty("账户冻结金额")
   private Integer frozenMoney;
 
   /**
@@ -153,6 +177,7 @@ public class Channel implements Serializable {
    */
   @TableField("certify_status")
   @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
+  @ApiModelProperty("认证状态,未认证n,已认证y")
   private ChannelCertifyStatusEnum certifyStatus;
 
   /**
@@ -160,30 +185,35 @@ public class Channel implements Serializable {
    */
   @TableField("verify_status")
   @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
+  @ApiModelProperty("审核状态")
   private ChannelVerifyStatusEnum verifyStatus;
 
   /**
    * 营业执照
    */
   @TableField("biz_license_pic")
+  @ApiModelProperty("营业执照")
   private String bizLicensePic;
 
   /**
    * 门头照片
    */
   @TableField("door_pic")
+  @ApiModelProperty("门头照片")
   private String doorPic;
 
   /**
    * 备注信息
    */
   @TableField("memo")
+  @ApiModelProperty("备注信息")
   private String memo;
 
   /**
    * 邀请码图片
    */
   @TableField("invite_pic")
+  @ApiModelProperty("邀请码图片")
   private String invitePic;
 
   /**
@@ -191,18 +221,21 @@ public class Channel implements Serializable {
    */
   @TableField("status")
   @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
+  @ApiModelProperty("状态,启用.停用")
   private ChannelStatusEnum status;
 
   /**
    * 创建时间
    */
   @TableField("created_time")
+  @ApiModelProperty("创建时间")
   private Date createdTime;
 
   /**
    * 更新时间
    */
   @TableField("updated_time")
+  @ApiModelProperty("更新时间")
   private Date updatedTime;
 
 

+ 79 - 0
mp-service/src/main/java/com/qs/mp/channel/domain/ChannelTicketTransfer.java

@@ -0,0 +1,79 @@
+package com.qs.mp.channel.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableField;
+
+import java.io.Serializable;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @describe 经销商盲票转让信息表实体类
+ * @auther quanshu
+ * @create 2022-04-21 10:47:03
+ */
+@TableName("mp_channel_ticket_transfer")
+@Data
+@ApiModel("经销商盲票转让信息表实体类")
+public class ChannelTicketTransfer implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    @ApiModelProperty("主键")
+    private Long id;
+
+    /**
+     * 转让人ID
+     */
+    @TableField("transfer_channel_id")
+    @ApiModelProperty("转让人ID")
+    private Long transferChannelId;
+
+    /**
+     * 拥有人ID
+     */
+    @TableField("channel_id")
+    @ApiModelProperty("拥有人ID")
+    private Long channelId;
+
+    /**
+     * 盲票组ID
+     */
+    @TableField("box_id")
+    @ApiModelProperty("盲票组ID")
+    private String boxId;
+
+    /**
+     * 盲票包ID
+     */
+    @TableField("pkg_id")
+    @ApiModelProperty("盲票包ID")
+    private String pkgId;
+
+    /**
+     * 创建时间
+     */
+    @TableField("created_time")
+    @ApiModelProperty("创建时间")
+    private Date createdTime;
+
+    /**
+     * 更新时间
+     */
+    @TableField("updated_time")
+    @ApiModelProperty("更新时间")
+    private Date updatedTime;
+
+
+}

+ 27 - 0
mp-service/src/main/java/com/qs/mp/channel/domain/param/ChannelMyTicketQueryParam.java

@@ -0,0 +1,27 @@
+package com.qs.mp.channel.domain.param;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.qs.mp.common.enums.TicketPkgSaleStatusEnum;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 经销商我的盲票查询入参类
+ * @author Cup
+ * @date 2022/4/21
+ */
+@ApiModel(value= "经销商我的盲票查询入参类")
+@Data
+public class ChannelMyTicketQueryParam {
+
+    @ApiModelProperty("销售状态 1待售,2销售中,3已售罄")
+    public TicketPkgSaleStatusEnum saleStatus;
+
+
+    @ApiModelProperty("搜索名称")
+    public String searchTitle;
+
+
+}

+ 29 - 0
mp-service/src/main/java/com/qs/mp/channel/domain/param/ChannelTicketTransferParam.java

@@ -0,0 +1,29 @@
+package com.qs.mp.channel.domain.param;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 经销商盲票转让入参类
+ * @author Cup
+ * @date 2022/4/21
+ */
+@ApiModel("经销商盲票转让入参类")
+@Data
+public class ChannelTicketTransferParam {
+
+
+    @ApiModelProperty("盲票组id")
+    private String boxId;
+
+    @ApiModelProperty("盲票包id")
+    private String pkgId;
+
+    @ApiModelProperty("受让人id")
+    private Long channelId;
+
+    @ApiModelProperty("受让人手机号")
+    private String mobile;
+
+}

+ 60 - 0
mp-service/src/main/java/com/qs/mp/channel/domain/vo/ChannelMyTicketVO.java

@@ -0,0 +1,60 @@
+package com.qs.mp.channel.domain.vo;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.qs.mp.common.enums.TicketPkgSaleStatusEnum;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 经销商我的盲票出参类
+ * @author Cup
+ * @date 2022/4/21
+ */
+@ApiModel("经销商我的盲票出参类")
+@Data
+public class ChannelMyTicketVO {
+
+    @ApiModelProperty("id")
+    private Long id;
+
+    @ApiModelProperty("盲票组ID")
+    private String boxId;
+
+    @ApiModelProperty("盲票包ID")
+    private String pkgId;
+
+
+    @ApiModelProperty("票包编号")
+    public String pkgNo;
+
+    @ApiModelProperty("主图")
+    private String picUrl;
+
+    @ApiModelProperty("票包名称")
+    private String title;
+
+    @ApiModelProperty("票的规格")
+    private Integer pkgUnit;
+
+    @ApiModelProperty("销售状态 1待售,2销售中,3已售罄")
+    @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
+    private TicketPkgSaleStatusEnum saleStatus;
+
+    @ApiModelProperty("销售数量")
+    private Integer saleQty;
+
+    @ApiModelProperty("面值")
+    private Integer facePrice;
+
+
+    @ApiModelProperty("创建时间")
+    private Date createdTime;
+
+
+
+
+}

+ 32 - 0
mp-service/src/main/java/com/qs/mp/channel/domain/vo/ChannelTicketTransferDetailVO.java

@@ -0,0 +1,32 @@
+package com.qs.mp.channel.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 盲票转让详情出参类
+ * @author Cup
+ * @date 2022/4/21
+ */
+@ApiModel("盲票转让详情出参类")
+@Data
+public class ChannelTicketTransferDetailVO {
+
+    @ApiModelProperty("盲票名称")
+    private String title;
+
+    @ApiModelProperty("票包编号")
+    private String pkgNo;
+
+    @ApiModelProperty("门店名称")
+    private String channelName;
+
+    @ApiModelProperty("手机号")
+    private String mobile;
+
+    @ApiModelProperty("转让时间")
+    private Date createdTime;
+}

+ 18 - 10
mp-service/src/main/java/com/qs/mp/channel/mapper/ChannelMapper.java

@@ -21,29 +21,37 @@ public interface ChannelMapper extends BaseMapper<Channel> {
 
 	/**
 	 * 获取我的下级渠道列表信息,支持翻页
-	 * 
-	 * @param channel
+	 *
+	 * @param wrapper
 	 * @return
 	 */
 	public List<ChannelVO> selectChannelVoList(@Param(Constants.WRAPPER) Wrapper<Channel> wrapper);
-	
+
+	/**
+	 * 获取我的下级渠道列表信息,支持翻页
+	 *
+	 * @param wrapper
+	 * @return
+	 */
+	public List<ChannelVO> selectChannelList(@Param(Constants.WRAPPER) Wrapper<Channel> wrapper);
+
 	/**
-	 * 根据ID查询渠道VO
+	 * 查询经销商列表
 	 *
-	 * @param userId
+	 * @param wrapper
 	 * @return
 	 */
-	public ChannelVO getChannelVoById(@Param("channelId") Long channelId);
-	
-	
+	public List<ChannelVO> selectSaleSiteList(@Param(Constants.WRAPPER) Wrapper<Channel> wrapper);
+
+
     /**
      * 查询渠道及其子渠道经销商总数
      * @param channelNo
      * @return
      */
     int getChannelSiteCnt(@Param("channelNo") String channelNo);
-    
-	
+
+
     /**
      * 统计新增的经销商数
      * @param wrapper

+ 16 - 0
mp-service/src/main/java/com/qs/mp/channel/mapper/ChannelOrderDetailMapper.java

@@ -1,7 +1,15 @@
 package com.qs.mp.channel.mapper;
 
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.qs.mp.channel.domain.Channel;
 import com.qs.mp.channel.domain.ChannelOrderDetail;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qs.mp.channel.domain.param.ChannelMyTicketQueryParam;
+import com.qs.mp.channel.domain.vo.ChannelMyTicketVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * @auther quanshu
@@ -10,4 +18,12 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  */
 public interface ChannelOrderDetailMapper extends BaseMapper<ChannelOrderDetail> {
 
+
+    /**
+     * 查询我的盲票列表
+     * @param wrapper
+     * @return
+     */
+    List<ChannelMyTicketVO> selectListMyTicketByChannelIdAndchannelMyTicketQueryParam(@Param(Constants.WRAPPER) Wrapper<ChannelOrderDetail> wrapper);
+
 }

+ 34 - 0
mp-service/src/main/java/com/qs/mp/channel/mapper/ChannelTicketTransferMapper.java

@@ -0,0 +1,34 @@
+package com.qs.mp.channel.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.qs.mp.channel.domain.ChannelTicketTransfer;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qs.mp.channel.domain.vo.ChannelMyTicketVO;
+import com.qs.mp.channel.domain.vo.ChannelTicketTransferDetailVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @auther quanshu
+ * @create 2022-04-21 10:47:03
+ * @describe 经销商盲票转让信息表mapper类
+ */
+public interface ChannelTicketTransferMapper extends BaseMapper<ChannelTicketTransfer> {
+
+    /**
+     * 获取已转让盲票列表
+     * @param queryWrapper
+     * @return
+     */
+    List<ChannelMyTicketVO> listTransferTicketList(@Param(Constants.WRAPPER) QueryWrapper<ChannelMyTicketVO> queryWrapper);
+
+    /**
+     * 获取已转让盲票详情
+     * @param queryWrapper
+     * @return
+     */
+    ChannelTicketTransferDetailVO getTicketTransferDetail(@Param(Constants.WRAPPER) QueryWrapper<ChannelTicketTransferDetailVO> queryWrapper);
+
+}

+ 11 - 0
mp-service/src/main/java/com/qs/mp/channel/service/IChannelOrderDetailService.java

@@ -2,6 +2,10 @@ package com.qs.mp.channel.service;
 
 import com.qs.mp.channel.domain.ChannelOrderDetail;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.qs.mp.channel.domain.param.ChannelMyTicketQueryParam;
+import com.qs.mp.channel.domain.vo.ChannelMyTicketVO;
+
+import java.util.List;
 
 /**
  * <p>
@@ -13,4 +17,11 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface IChannelOrderDetailService extends IService<ChannelOrderDetail> {
 
+    /**
+     * 获取我的盲票列表
+     * @param channelId 经销商id
+     * @param channelMyTicketQueryParam 查询参数
+     * @return
+     */
+    List<ChannelMyTicketVO> listMyTicket(Long channelId, ChannelMyTicketQueryParam channelMyTicketQueryParam);
 }

+ 20 - 4
mp-service/src/main/java/com/qs/mp/channel/service/IChannelService.java

@@ -43,13 +43,29 @@ public interface IChannelService extends IService<Channel> {
 
 
 	/**
-	 * 获取我的下级渠道、经销商列表信息,支持翻页
+	 * 获取我的下级渠道信息,支持翻页
 	 *
-	 * @param channel
+	 * @param queryWrapper
 	 * @return
 	 */
 	public List<ChannelVO> selectChannelVoList(Wrapper<Channel> queryWrapper);
 
+	/**
+	 * 获取我的下级渠道信息,统计经销商数和用户数,支持翻页
+	 *
+	 * @param queryWrapper
+	 * @return
+	 */
+	public List<ChannelVO> selectChannelList(Wrapper<Channel> queryWrapper);
+
+	/**
+	 * 获取经销商列表信息,支持翻页
+	 *
+	 * @param queryWrapper
+	 * @return
+	 */
+	public List<ChannelVO> selectSaleSiteList(Wrapper<Channel> queryWrapper);
+
 	/**
 	 * 根据用户ID查询渠道
 	 *
@@ -85,8 +101,8 @@ public interface IChannelService extends IService<Channel> {
 	 * 根据channelNo统计全部的经营数据
 	 */
 	public ChannelOperDataVO getChannelTotalOperData(String channelNo);
-	
-	
+
+
    /**
     * 统计新增的经销商数
     * @param wrapper

+ 44 - 0
mp-service/src/main/java/com/qs/mp/channel/service/IChannelTicketTransferService.java

@@ -0,0 +1,44 @@
+package com.qs.mp.channel.service;
+
+import com.qs.mp.channel.domain.ChannelTicketTransfer;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qs.mp.channel.domain.param.ChannelTicketTransferParam;
+import com.qs.mp.channel.domain.vo.ChannelMyTicketVO;
+import com.qs.mp.channel.domain.vo.ChannelTicketTransferDetailVO;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 经销商盲票转让信息表 服务类
+ * </p>
+ *
+ * @author quanshu
+ * @since 2022-04-21
+ */
+public interface IChannelTicketTransferService extends IService<ChannelTicketTransfer> {
+
+
+    /**
+     * 转让盲票
+     * @param transferChannelId     转让人id
+     * @param channelTicketTransferParam        转让参数
+     * @return
+     */
+    boolean transferTicket(Long transferChannelId, ChannelTicketTransferParam channelTicketTransferParam);
+
+    /**
+     * 获取已转让盲票列表
+     * @param transferChannelId     转让人id
+     * @return
+     */
+    List<ChannelMyTicketVO> listTransferTicketList(Long transferChannelId);
+
+    /**
+     * 根据id和转让人id查询盲票转让详情
+     * @param id
+     * @param transferChannelId
+     * @return
+     */
+    ChannelTicketTransferDetailVO getTicketTransferDetailById(Long id, Long transferChannelId);
+}

+ 26 - 0
mp-service/src/main/java/com/qs/mp/channel/service/impl/ChannelOrderDetailServiceImpl.java

@@ -1,11 +1,18 @@
 package com.qs.mp.channel.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qs.mp.channel.domain.ChannelOrderDetail;
+import com.qs.mp.channel.domain.param.ChannelMyTicketQueryParam;
+import com.qs.mp.channel.domain.vo.ChannelMyTicketVO;
 import com.qs.mp.channel.mapper.ChannelOrderDetailMapper;
 import com.qs.mp.channel.service.IChannelOrderDetailService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
+import java.util.Objects;
+
 /**
  * <p>
  * 经销商采购订单盲票包明细 服务实现类
@@ -17,4 +24,23 @@ import org.springframework.stereotype.Service;
 @Service
 public class ChannelOrderDetailServiceImpl extends ServiceImpl<ChannelOrderDetailMapper, ChannelOrderDetail> implements IChannelOrderDetailService {
 
+
+    @Override
+    public List<ChannelMyTicketVO> listMyTicket(Long channelId, ChannelMyTicketQueryParam channelMyTicketQueryParam) {
+        QueryWrapper<ChannelOrderDetail> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("t1.channel_id", channelId);
+        if (Objects.nonNull(channelMyTicketQueryParam.getSaleStatus())) {
+            queryWrapper.eq("t2.sale_status", channelMyTicketQueryParam.getSaleStatus());
+        }
+        if (StringUtils.isNotBlank(channelMyTicketQueryParam.getSearchTitle())) {
+            queryWrapper.nested(wrapper -> {
+                wrapper.likeRight("t2.pkg_no", channelMyTicketQueryParam.getSearchTitle())
+                        .or()
+                        .likeRight("t3.title", channelMyTicketQueryParam.getSearchTitle());
+            });
+
+        }
+        queryWrapper.orderByDesc("t1.created_time");
+        return this.baseMapper.selectListMyTicketByChannelIdAndchannelMyTicketQueryParam(queryWrapper);
+    }
 }

+ 20 - 4
mp-service/src/main/java/com/qs/mp/channel/service/impl/ChannelServiceImpl.java

@@ -2,6 +2,7 @@ package com.qs.mp.channel.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qs.mp.admin.domain.vo.IndexVO;
 import com.qs.mp.channel.domain.Channel;
@@ -24,6 +25,7 @@ import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 
 /**
  * <p>
@@ -122,6 +124,16 @@ public class ChannelServiceImpl extends ServiceImpl<ChannelMapper, Channel> impl
     return getBaseMapper().selectChannelVoList(queryWrapper);
   }
 
+  @Override
+  public List<ChannelVO> selectChannelList(Wrapper<Channel> queryWrapper) {
+    return getBaseMapper().selectChannelList(queryWrapper);
+  }
+
+  @Override
+  public List<ChannelVO> selectSaleSiteList(Wrapper<Channel> queryWrapper) {
+    return getBaseMapper().selectSaleSiteList(queryWrapper);
+  }
+
   @Override
   public Channel getChannelByUserId(Long userId) {
     return getBaseMapper().selectOne(
@@ -135,7 +147,11 @@ public class ChannelServiceImpl extends ServiceImpl<ChannelMapper, Channel> impl
 
   @Override
   public ChannelVO getChannelVoById(Long channelId) {
-    return getBaseMapper().getChannelVoById(channelId);
+    List<ChannelVO> channelVOList = getBaseMapper().selectChannelVoList(new QueryWrapper<Channel>().eq("t1.channel_id", channelId));
+    if (CollectionUtils.isEmpty(channelVOList)) {
+      return null;
+    }
+    return channelVOList.get(0);
   }
 
   @Override
@@ -164,11 +180,11 @@ public class ChannelServiceImpl extends ServiceImpl<ChannelMapper, Channel> impl
     // channelOperData.setNewUserCnt(newUserCnt);
     return channelOperData;
   }
-  
-  
+
+
   @Override
   public List<IndexVO> selectIndexSiteIncreaseList(Wrapper<Channel> wrapper) {
 	 return getBaseMapper().selectIndexSiteIncreaseList(wrapper);
   }
-  
+
 }

+ 76 - 0
mp-service/src/main/java/com/qs/mp/channel/service/impl/ChannelTicketTransferServiceImpl.java

@@ -0,0 +1,76 @@
+package com.qs.mp.channel.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.qs.mp.channel.domain.ChannelOrderDetail;
+import com.qs.mp.channel.domain.ChannelTicketTransfer;
+import com.qs.mp.channel.domain.param.ChannelTicketTransferParam;
+import com.qs.mp.channel.domain.vo.ChannelMyTicketVO;
+import com.qs.mp.channel.domain.vo.ChannelTicketTransferDetailVO;
+import com.qs.mp.channel.mapper.ChannelTicketTransferMapper;
+import com.qs.mp.channel.service.IChannelOrderDetailService;
+import com.qs.mp.channel.service.IChannelTicketTransferService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 经销商盲票转让信息表 服务实现类
+ * </p>
+ *
+ * @author quanshu
+ * @since 2022-04-21
+ */
+@Service
+public class ChannelTicketTransferServiceImpl extends ServiceImpl<ChannelTicketTransferMapper, ChannelTicketTransfer> implements IChannelTicketTransferService {
+
+
+    @Autowired
+    private IChannelOrderDetailService channelOrderDetailService;
+
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean transferTicket(Long transferChannelId, ChannelTicketTransferParam channelTicketTransferParam) {
+
+        // 转让盲票
+        ChannelTicketTransfer channelTicketTransfer = new ChannelTicketTransfer();
+        channelTicketTransfer.setTransferChannelId(transferChannelId);
+        channelTicketTransfer.setChannelId(channelTicketTransferParam.getChannelId());
+        channelTicketTransfer.setBoxId(channelTicketTransferParam.getBoxId());
+        channelTicketTransfer.setPkgId(channelTicketTransferParam.getPkgId());
+
+
+        // 记录盲票转让信息
+        this.save(channelTicketTransfer);
+
+        // 更新盲票拥有人
+        channelOrderDetailService.update(new LambdaUpdateWrapper<ChannelOrderDetail>()
+                .set(ChannelOrderDetail::getChannelId, channelTicketTransferParam.getChannelId())
+                .eq(ChannelOrderDetail::getPkgId, channelTicketTransferParam.getPkgId())
+                .eq(ChannelOrderDetail::getChannelId, transferChannelId));
+
+        return true;
+    }
+
+    @Override
+    public List<ChannelMyTicketVO> listTransferTicketList(Long transferChannelId) {
+        QueryWrapper<ChannelMyTicketVO> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("t.transfer_channel_id", transferChannelId);
+        queryWrapper.orderByDesc("t.created_time");
+        return this.baseMapper.listTransferTicketList(queryWrapper);
+    }
+
+    @Override
+    public ChannelTicketTransferDetailVO getTicketTransferDetailById(Long id, Long transferChannelId) {
+        QueryWrapper<ChannelTicketTransferDetailVO> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("t1.id", id);
+        queryWrapper.eq("t1.transfer_channel_id", transferChannelId);
+        return this.baseMapper.getTicketTransferDetail(queryWrapper);
+    }
+}

+ 2 - 1
mp-service/src/main/java/com/qs/mp/framework/redis/RedisKey.java

@@ -12,7 +12,8 @@ public enum RedisKey {
     WX_APP_TOKEN_KEY("app_token_key_{0}", "小程序app token"),
     CHANNEL_ORDER_KEY("channel_order_{0}", "经销商下的盲票采购单"),
     USER_TICKET_ORDER_KEY("user_ticket_order_key_{0}", "用户购票订单"),
-    USER_DELIVER_ORDER_KEY("user_deliver_order_key_{0}", "用户提货订单");
+    USER_DELIVER_ORDER_KEY("user_deliver_order_key_{0}", "用户提货订单"),
+    OFFLINE_TICKET_ID_KEY("offline_ticket_id_key_{0}", "线下盲票ID"),;
 
     public String keyTemplate;
     public String desc;

+ 46 - 0
mp-service/src/main/java/com/qs/mp/mq/impl/PulsarConsumerImpl.java

@@ -1,18 +1,28 @@
 package com.qs.mp.mq.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.qs.mp.admin.domain.Ticket;
 import com.qs.mp.admin.domain.TicketAwards;
 import com.qs.mp.admin.domain.TicketBox;
+import com.qs.mp.admin.domain.TicketPackage;
 import com.qs.mp.admin.service.ITicketBoxSerialService;
 import com.qs.mp.admin.service.ITicketBoxService;
+import com.qs.mp.admin.service.ITicketPackageService;
+import com.qs.mp.admin.service.ITicketService;
 import com.qs.mp.common.enums.CommStatusEnum;
 import com.qs.mp.common.enums.MqTopicType;
 import com.qs.mp.common.enums.TicketBoxStatusEnum;
+import com.qs.mp.common.enums.TicketPkgSaleStatusEnum;
+import com.qs.mp.common.enums.TicketTypeEnum;
 import com.qs.mp.common.enums.UserTicketOrderStatusEnum;
 import com.qs.mp.common.pulsar.PulsarConsumer;
 import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.user.domain.UserTicketOrder;
+import com.qs.mp.user.domain.UserTicketOrderItem;
+import com.qs.mp.user.service.IUserTicketOrderItemService;
 import com.qs.mp.user.service.IUserTicketOrderService;
+import java.util.List;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -36,6 +46,15 @@ public class PulsarConsumerImpl implements PulsarConsumer {
   @Autowired
   private IUserTicketOrderService userTicketOrderService;
 
+  @Autowired
+  private IUserTicketOrderItemService userTicketOrderItemService;
+
+  @Autowired
+  private ITicketPackageService ticketPackageService;
+
+  @Autowired
+  private ITicketService ticketService;
+
   @Override
   @Async("threadPoolTaskExecutor")
   public void wsConsumer(String topicType, String mqData) {
@@ -51,6 +70,33 @@ public class PulsarConsumerImpl implements PulsarConsumer {
   private void processTicketPayMsg(String mqData) {
     String orderId = mqData;
     UserTicketOrder ticketOrder = userTicketOrderService.getById(orderId);
+
+    TicketBox ticketBox = ticketBoxService.getById(ticketOrder.getBoxId());
+    if (ticketBox.getType() == TicketTypeEnum.OFFLINE) {
+      // 线下票更新销量,此处不做乐观锁控制,因为不用控制库存
+      ticketBoxService.update(
+          new LambdaUpdateWrapper<TicketBox>().set(TicketBox::getSaleQty,
+                  ticketBox.getSaleQty() + 1)
+              .eq(TicketBox::getBoxId, ticketBox.getBoxId()));
+    }
+
+
+    // 更新票组销售数量,此处只做累计,允许并发容错
+    List<UserTicketOrderItem> ticketOrderItemList = userTicketOrderItemService.list(new LambdaQueryWrapper<UserTicketOrderItem>()
+        .eq(UserTicketOrderItem::getOrderId, orderId));
+    for (UserTicketOrderItem orderItem : ticketOrderItemList) {
+      Ticket ticket = ticketService.getById(orderItem.getTicketId());
+      TicketPackage ticketPackage = ticketPackageService.getById(ticket.getPkgId());
+      ticketPackageService.update(new LambdaUpdateWrapper<TicketPackage>()
+          .set(TicketPkgSaleStatusEnum.WAIT_SALE == ticketPackage.getSaleStatus(),
+              TicketPackage::getSaleStatus, TicketPkgSaleStatusEnum.ON_SALE)
+          .set(TicketPkgSaleStatusEnum.ON_SALE == ticketPackage.getSaleStatus()
+                  && ticketPackage.getSaleQty() + 1 >= ticketPackage.getPkgUnit(),
+              TicketPackage::getSaleStatus, TicketPkgSaleStatusEnum.SALE_OUT)
+          .set(TicketPackage::getSaleQty, ticketPackage.getSaleQty() + 1)
+          .eq(TicketPackage::getPkgId, ticketPackage.getPkgId()));
+    }
+
     if (ticketOrder.getCommStatus() != CommStatusEnum.NO) {
       LogUtil.warn(logger, "收到盲票支付成功消息,订单结佣状态不是未结佣,忽略消息。orderId=" + orderId);
       return;

+ 6 - 0
mp-service/src/main/java/com/qs/mp/pay/service/IWalletService.java

@@ -21,6 +21,12 @@ public interface IWalletService {
    */
   JSONObject pay(BizTypeEnum bizType, String bizId, String openId, int money);
 
+  /**
+   * 订单退款
+   * @return
+   */
+  boolean refund(String orderNo, Integer refundAmount);
+
   /**
    *
    *订单支付回调统一处理函数

+ 34 - 10
mp-service/src/main/java/com/qs/mp/pay/service/impl/WalletServiceImpl.java

@@ -5,8 +5,10 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.qs.mp.channel.service.IChannelOrderService;
 import com.qs.mp.common.enums.BizTypeEnum;
+import com.qs.mp.common.enums.MqTopicType;
 import com.qs.mp.common.enums.PayOrderStatusEnum;
 import com.qs.mp.common.exception.ServiceException;
+import com.qs.mp.common.pulsar.PulsarClientService;
 import com.qs.mp.common.utils.DateUtils;
 import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.common.utils.StringUtils;
@@ -18,6 +20,7 @@ import com.qs.mp.system.service.id.BizIdGenerator;
 import com.qs.mp.user.service.IUserDeliverOrderService;
 import com.qs.mp.user.service.IUserTicketOrderService;
 import java.util.List;
+import org.apache.pulsar.client.api.PulsarClientException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -48,6 +51,9 @@ public class WalletServiceImpl implements IWalletService {
   @Autowired
   private IUserDeliverOrderService userDeliverOrderService;
 
+  @Autowired
+  private PulsarClientService pulsarClientService;
+
   @Autowired
   private BizIdGenerator bizIdGenerator;
 
@@ -121,17 +127,28 @@ public class WalletServiceImpl implements IWalletService {
   }
 
   @Override
-  @Transactional
+  public boolean refund(String orderNo, Integer refundAmount) {
+
+    String reqUrl = baseUrl + "/pay/refundOrder";
+
+    JSONObject sendData = new JSONObject();
+    sendData.put("shop_no", userPayShopNo);
+    sendData.put("timestamp",System.currentTimeMillis());
+    sendData.put("order_no",orderNo);
+    sendData.put("refund_amount", refundAmount);
+    sendData.put("order_remark", "测试退款");
+    sendData.put("type","sno");
+    sendData.put("sign",userPaySign);
+    System.err.println(sendData.toJSONString());
+    String result = OkHttpUtil.postJsonParams(reqUrl, sendData.toJSONString());
+    System.err.println(result);
+    return true;
+  }
+
+  @Override
   public void payOrderStatusHandle(PayOrder payOrder) {
     String orderNo = payOrder.getOrderId();
-    // 订单支付状态单独保存
-    LambdaUpdateWrapper<PayOrder> updateWrapper = new LambdaUpdateWrapper<>();
-    updateWrapper.eq(PayOrder::getOrderStatus, PayOrderStatusEnum.WAIT.getValue());
-    updateWrapper.eq(PayOrder::getOrderId, orderNo);
-    boolean ret = payOrderService.update(payOrder, updateWrapper);
-    if (!ret) {
-      throw new ServiceException("支付订单更新失败,orderNo:" + orderNo);
-    }
+
     //查询统一支付订单表,查询订单类型,然后根据不同类型做对应的逻辑处理
     //查询支付状态为1:支付成功,2:订单创建成功,等待支付。
     PayOrder order = payOrderService.getById(orderNo);
@@ -142,7 +159,14 @@ public class WalletServiceImpl implements IWalletService {
       channelOrderService.paySuccess(order);
     } else if (BizTypeEnum.TICKET_ORDER == order.getBizType()) {
       // 用户盲票购买订单支付成功,调用业务订单服务处理
-      userTicketOrderService.paySuccess(order);
+      boolean rst = userTicketOrderService.paySuccess(order);
+      try {
+        if (rst) {
+          pulsarClientService.producer(MqTopicType.ticket_pay, order.getBizId());
+        }
+      } catch (PulsarClientException e) {
+        LogUtil.error(logger, e, "盲票支付成功,发送异步消息失败. orderId:{0}", order.getBizId());
+      }
     } else if (BizTypeEnum.DELIVER_ORDER == order.getBizType()) {
       // 用户提货订单支付成功,调用业务订单服务处理
       userDeliverOrderService.paySuccess(order);

+ 79 - 85
mp-service/src/main/java/com/qs/mp/user/service/impl/UserTicketOrderServiceImpl.java

@@ -23,10 +23,10 @@ import com.qs.mp.channel.service.IChannelMoneyLogService;
 import com.qs.mp.channel.service.IChannelOrderDetailService;
 import com.qs.mp.channel.service.IChannelService;
 import com.qs.mp.channel.service.IChannelUserRelService;
+import com.qs.mp.common.core.redis.RedisCache;
 import com.qs.mp.common.enums.ChannelMoneyEnum;
 import com.qs.mp.common.enums.CommStatusEnum;
 import com.qs.mp.common.enums.ErrorCodeEnum;
-import com.qs.mp.common.enums.MqTopicType;
 import com.qs.mp.common.enums.TicketBoxStatusEnum;
 import com.qs.mp.common.enums.TicketPkgSaleStatusEnum;
 import com.qs.mp.common.enums.TicketStatusEnum;
@@ -34,19 +34,17 @@ import com.qs.mp.common.enums.TicketTypeEnum;
 import com.qs.mp.common.enums.UserCouponStatusEnum;
 import com.qs.mp.common.enums.UserTicketOrderStatusEnum;
 import com.qs.mp.common.exception.ServiceException;
-import com.qs.mp.common.pulsar.PulsarClientService;
 import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.common.utils.RSAUtil;
 import com.qs.mp.common.utils.StringUtils;
+import com.qs.mp.framework.redis.RedisKey;
 import com.qs.mp.pay.domain.PayOrder;
 import com.qs.mp.system.service.id.BizIdGenerator;
 import com.qs.mp.user.domain.UserCoupon;
-import com.qs.mp.user.domain.UserDeliverOrder;
 import com.qs.mp.user.domain.UserTicketOrder;
 import com.qs.mp.user.domain.UserTicketOrderItem;
 import com.qs.mp.user.domain.vo.TicketOrderSettleVO;
 import com.qs.mp.user.domain.vo.UserCoupon4OrderVO;
-import com.qs.mp.user.domain.vo.UserCouponVO;
 import com.qs.mp.user.domain.vo.UserShareVO;
 import com.qs.mp.user.mapper.UserTicketOrderMapper;
 import com.qs.mp.user.service.IUserCouponService;
@@ -57,7 +55,7 @@ import java.math.RoundingMode;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
-import org.apache.pulsar.client.api.PulsarClientException;
+import java.util.concurrent.TimeUnit;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -97,9 +95,6 @@ public class UserTicketOrderServiceImpl extends
   @Autowired
   private ITicketService ticketService;
 
-  @Autowired
-  private PulsarClientService pulsarClientService;
-
   @Autowired
   private IChannelService channelService;
 
@@ -115,9 +110,13 @@ public class UserTicketOrderServiceImpl extends
   @Autowired
   private BizIdGenerator bizIdGenerator;
 
+  @Autowired
+  private RedisCache redisCache;
+
   @Override
   @Transactional
-  public String submitOrder(Long userId, TicketOrderSettleVO orderSettleVO, UserShareVO userShareVO) {
+  public String submitOrder(Long userId, TicketOrderSettleVO orderSettleVO,
+      UserShareVO userShareVO) {
     if (StringUtils.isBlank(orderSettleVO.getTicketId())) {
       return createOnlineOrder(userId, orderSettleVO, userShareVO);
     }
@@ -126,7 +125,8 @@ public class UserTicketOrderServiceImpl extends
     return createOfflineOrder(userId, orderSettleVO);
   }
 
-  private String createOnlineOrder(Long userId, TicketOrderSettleVO orderSettleVO, UserShareVO userShareVO) {
+  private String createOnlineOrder(Long userId, TicketOrderSettleVO orderSettleVO,
+      UserShareVO userShareVO) {
     // 线上票更新票组销量,防止超卖
     TicketBox ticketBox = ticketBoxService.getById(orderSettleVO.getBoxId());
     if (ticketBox.getStatus() == TicketBoxStatusEnum.PUT_OFF
@@ -219,6 +219,13 @@ public class UserTicketOrderServiceImpl extends
     Ticket ticket = ticketService.getById(orderSettleVO.getTicketId());
     Assert.isTrue(ticket.getStatus() == TicketStatusEnum.NOT_PAY,
         "盲票已付款,ticketId:" + ticket.getTicketId());
+    if (null != redisCache.getCacheObject(
+        RedisKey.build(RedisKey.OFFLINE_TICKET_ID_KEY, ticket.getTicketId()))) {
+      LogUtil.error(logger, "线下盲票重复购买,ticketNo:{0}", ticket.getSerialNo());
+      throw new ServiceException("重复购买,请稍后再试");
+    }
+    redisCache.setCacheObject(RedisKey.build(RedisKey.OFFLINE_TICKET_ID_KEY, ticket.getTicketId()),
+        userId, 5, TimeUnit.MINUTES);
 
     // 核销优惠券
     String couponIds = verifyUserCoupon(orderSettleVO.getCouponList());
@@ -288,7 +295,8 @@ public class UserTicketOrderServiceImpl extends
     int sumTicket = 0;
     for (String orderId : orderIds) {
       UserTicketOrder userTicketOrder = getById(orderId);
-      Assert.isTrue(userTicketOrder.getResource() == TicketTypeEnum.ONLINE, "非在线盲票不用取消。boxId:" + boxId);
+      Assert.isTrue(userTicketOrder.getResource() == TicketTypeEnum.ONLINE,
+          "非在线盲票不用取消。boxId:" + boxId);
       if (!rollbackOrder(userTicketOrder)) {
         return false;
       }
@@ -300,13 +308,15 @@ public class UserTicketOrderServiceImpl extends
 
   private void rollbackBoxQty(String boxId, int qty) {
     TicketBox ticketBox = ticketBoxService.getById(boxId);
-    boolean updateBox = ticketBoxService.update(new LambdaUpdateWrapper<TicketBox>().set(TicketBox::getSaleQty,
-            ticketBox.getSaleQty() - qty)
-        .set(
-            ticketBox.getStatus() == TicketBoxStatusEnum.PUT_OFF && ticketBox.getManualOff() != 1,
-            TicketBox::getStatus, TicketBoxStatusEnum.PUT_ON)
-        .eq(TicketBox::getBoxId, ticketBox.getBoxId())
-        .eq(TicketBox::getSaleQty, ticketBox.getSaleQty()));
+    boolean updateBox = ticketBoxService.update(
+        new LambdaUpdateWrapper<TicketBox>().set(TicketBox::getSaleQty,
+                ticketBox.getSaleQty() - qty)
+            .set(
+                ticketBox.getStatus() == TicketBoxStatusEnum.PUT_OFF
+                    && ticketBox.getManualOff() != 1,
+                TicketBox::getStatus, TicketBoxStatusEnum.PUT_ON)
+            .eq(TicketBox::getBoxId, ticketBox.getBoxId())
+            .eq(TicketBox::getSaleQty, ticketBox.getSaleQty()));
     Assert.isTrue(updateBox, "取消过期未支付盲票购买订单,恢复票组销量失败。boxId:{0}" + boxId);
   }
 
@@ -340,8 +350,9 @@ public class UserTicketOrderServiceImpl extends
           .set(UserCoupon::getStatus, UserCouponStatusEnum.UNUSED)
           .set(UserCoupon::getVerifyTime, null)
           .in(UserCoupon::getId, userCouponIds));
-      Assert.isTrue(rst, "盲票购买订单取消时,反核销优惠券失败。orderId:" + userTicketOrder.getOrderId() + "userCouponIds:"
-          + userTicketOrder.getCouponInfo());
+      Assert.isTrue(rst,
+          "盲票购买订单取消时,反核销优惠券失败。orderId:" + userTicketOrder.getOrderId() + "userCouponIds:"
+              + userTicketOrder.getCouponInfo());
     }
 
     boolean rst = update(new LambdaUpdateWrapper<UserTicketOrder>().set(UserTicketOrder::getStatus,
@@ -379,11 +390,6 @@ public class UserTicketOrderServiceImpl extends
         Assert.isTrue(rst, "支付回调用户购票订单处理,更新订单明细的盲票ID失败,itemId:" + orderItem.getItemId());
       } else {
         ticket = ticketService.getById(orderItem.getTicketId());
-        // 线下票更新销量,此处不做乐观锁控制,因为不用控制库存
-        TicketBox ticketBox = ticketBoxService.getById(ticket.getBoxId());
-        ticketBoxService.update(
-            new LambdaUpdateWrapper<TicketBox>().set(TicketBox::getSaleQty, ticketBox.getSaleQty() + 1)
-                .eq(TicketBox::getBoxId, ticketBox.getBoxId()));
       }
 
       // 开幸运数字,更新ticket状态为已激活
@@ -394,14 +400,6 @@ public class UserTicketOrderServiceImpl extends
               .eq(Ticket::getTicketId, ticket.getTicketId()));
       Assert.isTrue(rtn, "支付回调用户购票订单处理,更新盲票状态失败,ticketId:" + ticket.getTicketId());
 
-      // 更新票组销售数量,此处只做累计,允许并发容错
-      TicketPackage ticketPackage = ticketPackageService.getById(ticket.getPkgId());
-      ticketPackageService.update(new LambdaUpdateWrapper<TicketPackage>()
-          .set(TicketPkgSaleStatusEnum.WAIT_SALE == ticketPackage.getSaleStatus(), TicketPackage::getSaleStatus, TicketPkgSaleStatusEnum.ON_SALE)
-          .set(TicketPkgSaleStatusEnum.ON_SALE == ticketPackage.getSaleStatus() && ticketPackage.getSaleQty()+1 >= ticketPackage.getPkgUnit(), TicketPackage::getSaleStatus, TicketPkgSaleStatusEnum.SALE_OUT)
-          .set(TicketPackage::getSaleQty, ticketPackage.getSaleQty() + 1)
-          .eq(TicketPackage::getPkgId, ticketPackage.getPkgId()));
-
     }
 
     // 更新订单状态为已完成
@@ -412,12 +410,6 @@ public class UserTicketOrderServiceImpl extends
             .eq(UserTicketOrder::getStatus, UserTicketOrderStatusEnum.NOT_PAY));
     Assert.isTrue(updateRst, "支付回调用户购票订单处理,更新订单状态失败,orderId:" + ticketOrder.getOrderId());
 
-    try {
-      pulsarClientService.producer(MqTopicType.ticket_pay, ticketOrder.getOrderId());
-    } catch (PulsarClientException e) {
-      LogUtil.error(logger, e, "盲票支付成功,发送异步消息失败. {0}", JSONObject.toJSONString(ticketOrder));
-    }
-
     return true;
   }
 
@@ -449,7 +441,8 @@ public class UserTicketOrderServiceImpl extends
         channelCommission.setSaleCommAmt(siteCommission.getSaleCommAmt());
         channelCommission.setCommRate(channel.getCommRate());
         channelCommission.setCommAmt(new BigDecimal(channelCommission.getSaleCommAmt()).multiply(
-            channelCommission.getCommRate()).divide(new BigDecimal(100), 0, RoundingMode.DOWN).intValue() - sumCommAmt);
+                channelCommission.getCommRate()).divide(new BigDecimal(100), 0, RoundingMode.DOWN)
+            .intValue() - sumCommAmt);
         channelCommissionService.save(channelCommission);
         sumCommAmt += channelCommission.getCommAmt();
       }
@@ -495,7 +488,8 @@ public class UserTicketOrderServiceImpl extends
     siteCommission.setSaleAmt(ticketOrder.getPayAmt());
     siteCommission.setSaleCommRate(ticketBox.getSaleCommRate());
     siteCommission.setSaleCommAmt(new BigDecimal(siteCommission.getSaleAmt()).multiply(
-        siteCommission.getSaleCommRate()).divide(new BigDecimal(100), 0, RoundingMode.DOWN).intValue());
+            siteCommission.getSaleCommRate()).divide(new BigDecimal(100), 0, RoundingMode.DOWN)
+        .intValue());
     siteCommission.setCommRate(channel.getCommRate());
     siteCommission.setCommAmt(new BigDecimal(siteCommission.getSaleCommAmt()).multiply(
         siteCommission.getCommRate()).divide(new BigDecimal(100), 0, RoundingMode.DOWN).intValue());
@@ -503,50 +497,50 @@ public class UserTicketOrderServiceImpl extends
     return siteCommission;
   }
 
-	@Override
-	public List<IndexVO> selectIndexPayAmtList(Wrapper<UserTicketOrder> wrapper) {
-		return getBaseMapper().selectIndexPayAmtList(wrapper);
-	}
-
-	@Override
-	public List<IndexVO> selectIndexPayUserCntList(Wrapper<UserTicketOrder> wrapper) {
-		return getBaseMapper().selectIndexPayUserCntList(wrapper);
-	}
-
-	@Override
-	public List<IndexVO> selectIndexDailyInfoList(Wrapper<UserTicketOrder> wrapper) {
-		return getBaseMapper().selectIndexDailyInfoList(wrapper);
-	}
-
-	@Override
-	public List<IndexVO> selectIndexTicketBoxTop(Wrapper<UserTicketOrder> wrapper) {
-		return getBaseMapper().selectIndexTicketBoxTop(wrapper);
-	}
-
-	@Override
-	public List<IndexVO> selectIndexTicketSiteTop(Wrapper<UserTicketOrder> wrapper) {
-		return getBaseMapper().selectIndexTicketSiteTop(wrapper);
-	}
-
-	@Override
-	public int getChannelTotalTicketNumCnt(String channelNo) {
-		return getBaseMapper().getChannelTotalTicketNumCnt(channelNo);
-	}
-
-	@Override
-	public int getSaleSiteTotalTicketNumCnt(Long channelId) {
-		return getBaseMapper().getSaleSiteTotalTicketNumCnt(channelId);
-	}
-
-	@Override
-	public TicketCntVO getTicketSaleCnt(Long channelId) {
-		return getBaseMapper().getTicketSaleCnt(channelId);
-	}
-
-	@Override
-	public List<TicketCntVO> listTicketSaleCnt(Wrapper<UserTicketOrder> queryWrapper) {
-		return getBaseMapper().listTicketSaleCnt(queryWrapper);
-	}
+  @Override
+  public List<IndexVO> selectIndexPayAmtList(Wrapper<UserTicketOrder> wrapper) {
+    return getBaseMapper().selectIndexPayAmtList(wrapper);
+  }
+
+  @Override
+  public List<IndexVO> selectIndexPayUserCntList(Wrapper<UserTicketOrder> wrapper) {
+    return getBaseMapper().selectIndexPayUserCntList(wrapper);
+  }
+
+  @Override
+  public List<IndexVO> selectIndexDailyInfoList(Wrapper<UserTicketOrder> wrapper) {
+    return getBaseMapper().selectIndexDailyInfoList(wrapper);
+  }
+
+  @Override
+  public List<IndexVO> selectIndexTicketBoxTop(Wrapper<UserTicketOrder> wrapper) {
+    return getBaseMapper().selectIndexTicketBoxTop(wrapper);
+  }
+
+  @Override
+  public List<IndexVO> selectIndexTicketSiteTop(Wrapper<UserTicketOrder> wrapper) {
+    return getBaseMapper().selectIndexTicketSiteTop(wrapper);
+  }
+
+  @Override
+  public int getChannelTotalTicketNumCnt(String channelNo) {
+    return getBaseMapper().getChannelTotalTicketNumCnt(channelNo);
+  }
+
+  @Override
+  public int getSaleSiteTotalTicketNumCnt(Long channelId) {
+    return getBaseMapper().getSaleSiteTotalTicketNumCnt(channelId);
+  }
+
+  @Override
+  public TicketCntVO getTicketSaleCnt(Long channelId) {
+    return getBaseMapper().getTicketSaleCnt(channelId);
+  }
+
+  @Override
+  public List<TicketCntVO> listTicketSaleCnt(Wrapper<UserTicketOrder> queryWrapper) {
+    return getBaseMapper().listTicketSaleCnt(queryWrapper);
+  }
 
 
 }

+ 49 - 9
mp-service/src/main/resources/mapper/channel/ChannelMapper.xml

@@ -56,18 +56,58 @@
 		and (t1.channel_no like concat(#{channelNo}, '.%') or t1.channel_no = #{channelNo})
     </select>
 
-     <!-- 查询渠道信息 -->
-    <select id="getChannelVoById" resultType="com.qs.mp.channel.domain.vo.ChannelVO">
-		select t1.* , t2.name parentName
-		from mp_channel t1
-		left join mp_channel t2 on t1.parent_id = t2.channel_id
-		where t1.channel_id = #{channelId}
+  <!-- 查询子渠道信息 -->
+  <select id="selectChannelList" resultType="com.qs.mp.channel.domain.vo.ChannelVO">
+    select t1.* , t2.name parentName, t3.site_cnt, t4.child_cnt, t5.user_cnt
+    from mp_channel t1
+           left join mp_channel t2 on t1.parent_id = t2.channel_id
+           left join (select q1.channel_id, count(q2.channel_id) as site_cnt
+                      from mp_channel q1
+                             left join mp_channel q2 on q2.channel_no like concat(q1.channel_id, '.%')
+                      where q1.level > 0 and q2.level= 0
+                      group by q1.channel_id) t3 on t3.channel_id = t1.channel_id
+           left join (select q1.channel_id, count(q2.channel_id) as child_cnt
+                      from mp_channel q1
+                             left join mp_channel q2 on q2.channel_no like concat(q1.channel_id, '.%')
+                      where q1.level > 0 and q2.level> 0
+                      group by q1.channel_id) t4 on t4.channel_id = t1.channel_id
+           left join (select q1.channel_id,sum(q2.user_cnt) as user_cnt
+                      from mp_channel q1
+                             left join (select b.channel_no, a.channel_id, count(a.id) AS user_cnt
+                                        from mp_channel_user_rel a
+                                               left join mp_channel b on a.channel_id=b.channel_id
+                                        group by a.channel_id, b.channel_no) q2 on q2.channel_no like concat(q1.channel_no, '.%')
+                      group by q1.channel_id
+                    ) t5 on t5.channel_id=t1.channel_id
+      ${ew.customSqlSegment}
+  </select>
+
+     <!-- 查询经销商列表信息 -->
+    <select id="selectSaleSiteList" resultType="com.qs.mp.channel.domain.vo.ChannelVO">
+      select t1.channel_id as channelId, t1.channel_no, t1.name, t1.parent_id, t1.level, t1.site_type, t1.site_name, t1.comm_rate as commRate, t1.province, t1.province_id, t1.city, t1.city_id, t1.area, t1.area_id, t1.address, t1.contact, t1.mobile, t1.user_id, t1.certify_status, t1.verify_status, t1.status, t1.created_time, t1.updated_time ,
+             t2.off_line_qty_cnt, t2.off_line_sale_cnt, t4.sale_qty-t2.off_line_sale_cnt as on_line_sale_cnt, t3.user_cnt
+      from mp_channel t1
+             left join (
+        select channel_id, SUM(  b.pkg_unit - b.sale_qty ) AS off_line_qty_cnt,
+               SUM(  b.sale_qty  ) AS off_line_sale_cnt
+        from mp_channel_order_detail a
+               left join mp_ticket_package b on a.pkg_id=b.pkg_id
+        group by a.channel_id) t2 on t1.channel_id = t2.channel_id
+             left join (
+        select channel_id, count(*) AS user_cnt
+        from mp_channel_user_rel
+        group by channel_id) t3 on t1.channel_id = t3.channel_id
+             left join (
+        select channel_id, count(*) AS sale_qty
+        from mp_channel_commission
+        group by channel_id) t4 on t1.channel_id = t4.channel_id
+        ${ew.customSqlSegment}
 	</select>
-	
-	
+
+
 	<!-- 统计新增经销商数列表 -->
     <select id="selectIndexSiteIncreaseList" resultType="com.qs.mp.admin.domain.vo.IndexVO">
-		select 
+		select
           DATE_FORMAT(t1.created_time, '%Y%m%d') AS time,
           COUNT(t1.channel_id) AS newSiteCnt
 	     from `mp_channel` t1

+ 19 - 0
mp-service/src/main/resources/mapper/channel/ChannelOrderDetailMapper.xml

@@ -20,4 +20,23 @@
         id, order_id, channel_id, box_id, pkg_id, start_sn, end_sn, created_time, updated_time
     </sql>
 
+    <select id="selectListMyTicketByChannelIdAndchannelMyTicketQueryParam"
+            resultType="com.qs.mp.channel.domain.vo.ChannelMyTicketVO">
+        SELECT t1.id,
+               t1.channel_id,
+               t1.box_id,
+               t1.pkg_id,
+               t1.created_time,
+               t2.pkg_no,
+               t2.sale_status,
+               t2.sale_qty,
+               t2.pkg_unit,
+               t3.title,
+               t3.pic_url,
+               t3.face_price
+        FROM mp_channel_order_detail t1
+         LEFT JOIN mp_ticket_package t2 ON t1.pkg_id = t2.pkg_id
+         LEFT JOIN mp_ticket_box t3 ON t2.box_id = t3.box_id
+        ${ew.customSqlSegment}
+    </select>
 </mapper>

+ 53 - 0
mp-service/src/main/resources/mapper/channel/ChannelTicketTransferMapper.xml

@@ -0,0 +1,53 @@
+<?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.qs.mp.channel.mapper.ChannelTicketTransferMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.qs.mp.channel.domain.ChannelTicketTransfer">
+        <id column="id" property="id" />
+        <result column="transfer_channel_id" property="transferChannelId" />
+        <result column="channel_id" property="channelId" />
+        <result column="box_id" property="boxId" />
+        <result column="pkg_id" property="pkgId" />
+        <result column="created_time" property="createdTime" />
+        <result column="updated_time" property="updatedTime" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, transfer_channel_id, channel_id, box_id, pkg_id, created_time, updated_time
+    </sql>
+
+    <select id="listTransferTicketList" resultType="com.qs.mp.channel.domain.vo.ChannelMyTicketVO">
+        SELECT t.id,
+               t1.channel_id,
+               t1.box_id,
+               t1.pkg_id,
+               t1.created_time,
+               t2.pkg_no,
+               t2.sale_status,
+               t2.sale_qty,
+               t2.pkg_unit,
+               t3.title,
+               t3.pic_url,
+               t3.face_price
+        FROM mp_channel_ticket_transfer t
+         Left JOIN mp_channel_order_detail t1 ON t.pkg_id = t1.pkg_id
+         LEFT JOIN mp_ticket_package t2 ON t1.pkg_id = t2.pkg_id
+         LEFT JOIN mp_ticket_box t3 ON t2.box_id = t3.box_id
+        ${ew.customSqlSegment}
+    </select>
+
+    <select id="getTicketTransferDetail" resultType="com.qs.mp.channel.domain.vo.ChannelTicketTransferDetailVO">
+        SELECT t4.title,
+               t3.pkg_no,
+               t2.name channelName,
+               t2.mobile,
+               t1.created_time
+        FROM mp_channel_ticket_transfer t1
+         LEFT JOIN mp_channel t2 ON t1.channel_id = t2.channel_id
+         LEFT JOIN mp_ticket_package t3 ON t1.pkg_id = t3.pkg_id
+         LEFT JOIN mp_ticket_box t4 ON t1.box_id = t4.box_id
+        ${ew.customSqlSegment}
+    </select>
+</mapper>