| @@ -1,7 +1,10 @@ | |||||
| ALTER TABLE `wx_game` | ALTER TABLE `wx_game` | ||||
| ADD COLUMN `play_credit_limit` int(11) NOT NULL DEFAULT -1 AFTER `award_limit`, | ADD COLUMN `play_credit_limit` int(11) NOT NULL DEFAULT -1 AFTER `award_limit`, | ||||
| ADD COLUMN `play_credit` int(11) AFTER `play_credit_limit`; | |||||
| ADD COLUMN `play_credit` int(11) NOT NULL DEFAULT 0 AFTER `play_credit_limit`; | |||||
| ADD COLUMN `limit_type` int(11) NOT NULL DEFAULT 0 COMMENT '次数规则0:总次数 1:每天' AFTER `play_credit`; | |||||
| ALTER TABLE `wx_game_action_log` | ALTER TABLE `wx_game_action_log` | ||||
| ADD COLUMN `type` int(11) NOT NULL DEFAULT 0 AFTER `create_time`; | |||||
| ADD COLUMN `type` int(11) NOT NULL DEFAULT 0 AFTER `create_time`, | |||||
| ADD COLUMN `used_credit` int(11) NOT NULL DEFAULT 0 AFTER `type`, | |||||
| ADD COLUMN `add_credit` int(11) NOT NULL DEFAULT 0 AFTER `used_credit`; | |||||
| @@ -69,8 +69,8 @@ public class WxCreditHistoryController extends BaseController{ | |||||
| } | } | ||||
| wxCreditHistory.setTenantId(wxCUser.getFinalTenantId()); | wxCreditHistory.setTenantId(wxCUser.getFinalTenantId()); | ||||
| wxCreditHistory.setCUserId(wxCUser.getId()); | |||||
| wxCreditHistory.setOperatorId(wxCUser.getId()); | |||||
| wxCreditHistory.setCUserId(wxCUser.getUserId()); | |||||
| wxCreditHistory.setOperatorId(wxCUser.getUserId()); | |||||
| wxCreditHistory.setOperatorType(EnumUserType.CUSER.getCode()); | wxCreditHistory.setOperatorType(EnumUserType.CUSER.getCode()); | ||||
| if(wxCreditHistory.getCreditType().equals(EnumScoreType.GAME_ADD_CREDIT.getCode())){ | if(wxCreditHistory.getCreditType().equals(EnumScoreType.GAME_ADD_CREDIT.getCode())){ | ||||
| @@ -12,8 +12,10 @@ import io.swagger.annotations.ApiOperation; | |||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.transaction.annotation.Transactional; | |||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||
| import java.util.List; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| @RestController | @RestController | ||||
| @@ -87,4 +89,85 @@ public class WxGameController extends BaseController { | |||||
| } | } | ||||
| } | } | ||||
| @ApiOperation("免费玩游戏") | |||||
| @PostMapping("freeGameGo") | |||||
| @ApiImplicitParams({ | |||||
| @ApiImplicitParam(name = "gameId", value = "游戏ID", dataType = "String", paramType = "query", required = true)}) | |||||
| public ResultData freeGameGo(@RequestBody Map<String,String> paramMap) { | |||||
| try { | |||||
| Long gameIdL = Long.valueOf(paramMap.get("gameId")); | |||||
| if(gameIdL == null){ | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||||
| } | |||||
| Map<String,Object> data = (Map<String, Object>) wxGameService.getCount(gameIdL, getMemberId()).data; | |||||
| if(data == null){ | |||||
| return new ResultData(ErrorCode.GAME_NOT_FOUND); | |||||
| } | |||||
| int playLimit = (int) data.get("playLimit"); | |||||
| if(playLimit < 0){ | |||||
| return new ResultData(ErrorCode.GAME_NOT_COUNT); | |||||
| } | |||||
| int AwardLimit = (int) data.get("AwardLimit"); | |||||
| int AwardCount = (int) data.get("AwardCount"); | |||||
| if(AwardLimit != 0 && AwardCount >= AwardLimit){ | |||||
| return new ResultData(ErrorCode.GAME_NOT_WIN_COUNT); | |||||
| } | |||||
| int playCount = (int) data.get("playCount"); | |||||
| if((playLimit > 0 && playCount >= playLimit) || playLimit < 0){ | |||||
| return new ResultData(ErrorCode.GAME_NOT_HAVE_COUNT); | |||||
| } | |||||
| ResultData resultData = wxGameService.luckDraw(gameIdL, getMemberId(),0); | |||||
| removeCacheCUser(); | |||||
| return resultData; | |||||
| } catch (Exception e){ | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_ERROR); | |||||
| } | |||||
| } | |||||
| @ApiOperation("积分玩游戏") | |||||
| @PostMapping("freeCridetGameGo") | |||||
| @ApiImplicitParams({ | |||||
| @ApiImplicitParam(name = "gameId", value = "游戏ID", dataType = "String", paramType = "query", required = true)}) | |||||
| public ResultData freeCridetGameGo(@RequestBody Map<String,String> paramMap) { | |||||
| try { | |||||
| Long gameIdL = Long.valueOf(paramMap.get("gameId")); | |||||
| if(gameIdL == null){ | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||||
| } | |||||
| Map<String,Object> data = (Map<String, Object>) wxGameService.getCount(gameIdL, getMemberId()).data; | |||||
| if(data == null){ | |||||
| return new ResultData(ErrorCode.GAME_NOT_FOUND); | |||||
| } | |||||
| int playLimit = (int) data.get("playLimit"); | |||||
| if(playLimit < 0){ | |||||
| return new ResultData(ErrorCode.GAME_NOT_COUNT); | |||||
| } | |||||
| int AwardLimit = (int) data.get("AwardLimit"); | |||||
| int AwardCount = (int) data.get("AwardCount"); | |||||
| if(AwardLimit != 0 && AwardCount >= AwardLimit){ | |||||
| return new ResultData(ErrorCode.GAME_NOT_WIN_COUNT); | |||||
| } | |||||
| int playCount = (int) data.get("playCount"); | |||||
| if((playLimit > 0 && playCount >= playLimit) || playLimit < 0){ | |||||
| int playCreditLimit = (int) data.get("playCreditLimit"); | |||||
| int playCreditCount = (int) data.get("playCreditCount"); | |||||
| if((playCreditLimit > 0 && playCreditCount >= playCreditLimit) || playCreditLimit < 0){//积分不能玩了 | |||||
| return new ResultData(ErrorCode.GAME_NOT_HAVEC_COUNT); | |||||
| } | |||||
| }else{ | |||||
| return new ResultData(ErrorCode.GAME_HAVE_COUNT); | |||||
| } | |||||
| ResultData resultData = wxGameService.cridetLuckDraw(gameIdL, getMemberId()); | |||||
| removeCacheCUser(); | |||||
| return resultData; | |||||
| } catch (Exception e){ | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_ERROR); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -1,6 +1,5 @@ | |||||
| package com.iformall.controller; | package com.iformall.controller; | ||||
| import com.alibaba.fastjson.JSONObject; | |||||
| import com.github.pagehelper.PageInfo; | import com.github.pagehelper.PageInfo; | ||||
| import com.iformall.common.ErrorCode; | import com.iformall.common.ErrorCode; | ||||
| import com.iformall.common.Result; | import com.iformall.common.Result; | ||||
| @@ -30,12 +29,10 @@ import org.slf4j.LoggerFactory; | |||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.beans.factory.annotation.Qualifier; | import org.springframework.beans.factory.annotation.Qualifier; | ||||
| import org.springframework.data.redis.core.RedisTemplate; | import org.springframework.data.redis.core.RedisTemplate; | ||||
| import org.springframework.data.redis.core.ValueOperations; | |||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||
| import java.util.Date; | import java.util.Date; | ||||
| import java.util.Map; | import java.util.Map; | ||||
| import java.util.concurrent.TimeUnit; | |||||
| @RestController | @RestController | ||||
| @RequestMapping("/api/order/") | @RequestMapping("/api/order/") | ||||
| @@ -71,161 +68,161 @@ public class WxOrderController extends BaseController { | |||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| return new ResultData(Result.ERROR,e.getMessage()); | return new ResultData(Result.ERROR,e.getMessage()); | ||||
| } | } | ||||
| return saveOrder(orderSaveDto,memberId,EnumPayWay.PAY_WAY_WECHAT); | |||||
| return wxOrderService.saveOrder(orderSaveDto,memberId,EnumPayWay.PAY_WAY_WECHAT,getTenantInfo()); | |||||
| } | } | ||||
| private ResultData saveOrder(OrderSaveDto orderSaveDto,Long cUserId,EnumPayWay payWay) { | |||||
| logger.info("OrderSave: " + orderSaveDto); | |||||
| if (orderSaveDto.getCouponChannelId() == null) { | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "couponChannelId不能为空"); | |||||
| } | |||||
| WxCouponChannel wxCouponChannel = wxCouponChannelService.getById(orderSaveDto.getCouponChannelId(),getTenantInfo().getTenantId()); | |||||
| if (wxCouponChannel == null) { | |||||
| logger.error("couponChannelId find error, " + orderSaveDto.getCouponChannelId()); | |||||
| return new ResultData(ErrorCode.COUPON_CHANNEL_IS_TAKE_OFF); | |||||
| } | |||||
| ResultData resultData = couponChannelCheck(orderSaveDto, wxCouponChannel); | |||||
| if (resultData != null) return resultData; | |||||
| WxCUserBasicInfo wxCUserBasicInfo = wxCUserBasicInfoService.getById(cUserId,getFinalTenantId()); | |||||
| if (wxCUserBasicInfo != null && wxCUserBasicInfo.getStatus().equals(EnumCUserBasicInfoStatus.LOCKED.getCode())) { | |||||
| logger.info("会员权益被锁定:cUserId:" + cUserId); | |||||
| return new ResultData(ErrorCode.MEMBER_IS_LOCKED); | |||||
| } | |||||
| WxCoupon coupon = wxCouponService.getById(wxCouponChannel.getCouponId(),wxCouponChannel.getTenantId()); | |||||
| if (null == coupon) { | |||||
| return new ResultData(ErrorCode.COUPON_IS_EMPTY); | |||||
| } | |||||
| if (coupon.getStatus().equals(EnumCouponStatus.COUPON_STATUS_TAKE_OFFF.getCode())) { | |||||
| return new ResultData(ErrorCode.COUPON_IS_TAKE_OFF); | |||||
| } | |||||
| //判断是否是拼团订单,如果是拼团订单,判断现在进行中的,和已完成的数量是否超出券的限制 | |||||
| if (coupon.getType().equals(EnumCouponType.COUPON_GROUP.getCode())) { | |||||
| int ordercount = wxOrderService.countUserCouponGroupOrder(cUserId,coupon.getId(),coupon.getTenantId()); | |||||
| if (ordercount>=coupon.getUseLimitQuantity()) { | |||||
| return new ResultData(ErrorCode.COUPON_IS_TAKE_OFF.getCode(),"您当前此券的有效拼团数量达到券的限购次数。"); | |||||
| } | |||||
| } | |||||
| WxCouponCVo wxCouponCVo = null; | |||||
| String key = "cc:" + orderSaveDto.getCouponChannelId(); | |||||
| ValueOperations<String, WxCouponCVo> operations = cdRedisTemplate.opsForValue(); | |||||
| // 缓存 | |||||
| boolean hasKey = cdRedisTemplate.hasKey(key); | |||||
| if (hasKey) { | |||||
| // 从缓存获取用户信息 | |||||
| wxCouponCVo = operations.get(key); | |||||
| } else { | |||||
| // 游戏没有入缓存,需要从数据库中读取 | |||||
| wxCouponCVo = wxCouponChannelService.findDetailVo(orderSaveDto.getCouponChannelId(),wxCouponChannel.getTenantId()); | |||||
| if (wxCouponCVo != null) { | |||||
| // 游戏优化,进缓存 | |||||
| cdRedisTemplate.opsForValue().set(key, wxCouponCVo, 3600, TimeUnit.SECONDS); | |||||
| } | |||||
| } | |||||
| if (wxCouponCVo == null) { | |||||
| return new ResultData(ErrorCode.COUPON_IS_EMPTY); | |||||
| } | |||||
| //此处判断是否存在绝对保证库存不超卖的缓存,如果没有,则把当前的库存设置为最大值。如果有,则是后台设置的时候保存的,以那个为准。 | |||||
| boolean hascache = redisLock.hasCouponStockCache(wxCouponCVo.getCouponId()); | |||||
| if (!hascache) { | |||||
| long time = System.currentTimeMillis() + RedisLock.TIMEOUT; | |||||
| String timeStr = String.valueOf(time); | |||||
| boolean stocksetlock = redisLock.lock("couponLockStockSetByOrder_"+coupon.getId(), timeStr); | |||||
| if (stocksetlock) { | |||||
| try { | |||||
| if (!redisLock.hasCouponStockCache(wxCouponCVo.getCouponId())) { | |||||
| redisLock.setCouponStock(wxCouponCVo.getCouponId(), coupon.getRemainInventory()); | |||||
| } | |||||
| }catch(Exception e) { | |||||
| logger.error("save order stock cache error.",e); | |||||
| }finally { | |||||
| redisLock.unlock("couponLockStockSetByOrder_"+coupon.getId(), timeStr); | |||||
| } | |||||
| }else { | |||||
| redisLock.unlock("couponLockStockSetByOrder_"+coupon.getId(), timeStr); | |||||
| } | |||||
| } | |||||
| resultData = couponUserCheck(wxCUserBasicInfo, wxCouponCVo); | |||||
| if (resultData != null) return resultData; | |||||
| Long couponId = orderSaveDto.getCouponId() == null ? wxCouponChannel.getCouponId() : orderSaveDto.getCouponId(); | |||||
| if (couponId == null) { | |||||
| logger.error("couponChannelId或者couponId不能为空"); | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "couponChannelId或者couponId不能为空"); | |||||
| } | |||||
| // 是否砍价 | |||||
| boolean isPress = orderSaveDto.getPress() != null ? orderSaveDto.getPress() : false; | |||||
| try { | |||||
| WxOrder order = wxOrderService.saveOrderForCoupon(wxCUserBasicInfo, coupon, orderSaveDto, isPress,payWay); | |||||
| return new ResultData(order); | |||||
| } catch (MallinkException e) { | |||||
| logger.error(e.getMessage()); | |||||
| return new ResultData(e.getErrorCode(), e.getMessage()); | |||||
| } catch (Exception e) { | |||||
| logger.error(e.getMessage()); | |||||
| return new ResultData(ErrorCode.ORDER_IS_FAIL, e.getMessage()); | |||||
| } | |||||
| } | |||||
| // private ResultData saveOrder(OrderSaveDto orderSaveDto,Long cUserId,EnumPayWay payWay) { | |||||
| // logger.info("OrderSave: " + orderSaveDto); | |||||
| // if (orderSaveDto.getCouponChannelId() == null) { | |||||
| // return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "couponChannelId不能为空"); | |||||
| // } | |||||
| // WxCouponChannel wxCouponChannel = wxCouponChannelService.getById(orderSaveDto.getCouponChannelId(),getTenantInfo().getTenantId()); | |||||
| // if (wxCouponChannel == null) { | |||||
| // logger.error("couponChannelId find error, " + orderSaveDto.getCouponChannelId()); | |||||
| // return new ResultData(ErrorCode.COUPON_CHANNEL_IS_TAKE_OFF); | |||||
| // } | |||||
| // ResultData resultData = couponChannelCheck(orderSaveDto, wxCouponChannel); | |||||
| // if (resultData != null) return resultData; | |||||
| // | |||||
| // WxCUserBasicInfo wxCUserBasicInfo = wxCUserBasicInfoService.getById(cUserId,getFinalTenantId()); | |||||
| // if (wxCUserBasicInfo != null && wxCUserBasicInfo.getStatus().equals(EnumCUserBasicInfoStatus.LOCKED.getCode())) { | |||||
| // logger.info("会员权益被锁定:cUserId:" + cUserId); | |||||
| // return new ResultData(ErrorCode.MEMBER_IS_LOCKED); | |||||
| // } | |||||
| // | |||||
| // WxCoupon coupon = wxCouponService.getById(wxCouponChannel.getCouponId(),wxCouponChannel.getTenantId()); | |||||
| // if (null == coupon) { | |||||
| // return new ResultData(ErrorCode.COUPON_IS_EMPTY); | |||||
| // } | |||||
| // if (coupon.getStatus().equals(EnumCouponStatus.COUPON_STATUS_TAKE_OFFF.getCode())) { | |||||
| // return new ResultData(ErrorCode.COUPON_IS_TAKE_OFF); | |||||
| // } | |||||
| // //判断是否是拼团订单,如果是拼团订单,判断现在进行中的,和已完成的数量是否超出券的限制 | |||||
| // if (coupon.getType().equals(EnumCouponType.COUPON_GROUP.getCode())) { | |||||
| // int ordercount = wxOrderService.countUserCouponGroupOrder(cUserId,coupon.getId(),coupon.getTenantId()); | |||||
| // if (ordercount>=coupon.getUseLimitQuantity()) { | |||||
| // return new ResultData(ErrorCode.COUPON_IS_TAKE_OFF.getCode(),"您当前此券的有效拼团数量达到券的限购次数。"); | |||||
| // } | |||||
| // } | |||||
| // | |||||
| // WxCouponCVo wxCouponCVo = null; | |||||
| // | |||||
| // String key = "cc:" + orderSaveDto.getCouponChannelId(); | |||||
| // ValueOperations<String, WxCouponCVo> operations = cdRedisTemplate.opsForValue(); | |||||
| // // 缓存 | |||||
| // boolean hasKey = cdRedisTemplate.hasKey(key); | |||||
| // if (hasKey) { | |||||
| // // 从缓存获取用户信息 | |||||
| // wxCouponCVo = operations.get(key); | |||||
| // } else { | |||||
| // // 游戏没有入缓存,需要从数据库中读取 | |||||
| // wxCouponCVo = wxCouponChannelService.findDetailVo(orderSaveDto.getCouponChannelId(),wxCouponChannel.getTenantId()); | |||||
| // if (wxCouponCVo != null) { | |||||
| // // 游戏优化,进缓存 | |||||
| // cdRedisTemplate.opsForValue().set(key, wxCouponCVo, 3600, TimeUnit.SECONDS); | |||||
| // } | |||||
| // } | |||||
| // if (wxCouponCVo == null) { | |||||
| // return new ResultData(ErrorCode.COUPON_IS_EMPTY); | |||||
| // } | |||||
| // | |||||
| // //此处判断是否存在绝对保证库存不超卖的缓存,如果没有,则把当前的库存设置为最大值。如果有,则是后台设置的时候保存的,以那个为准。 | |||||
| // boolean hascache = redisLock.hasCouponStockCache(wxCouponCVo.getCouponId()); | |||||
| // if (!hascache) { | |||||
| // long time = System.currentTimeMillis() + RedisLock.TIMEOUT; | |||||
| // String timeStr = String.valueOf(time); | |||||
| // boolean stocksetlock = redisLock.lock("couponLockStockSetByOrder_"+coupon.getId(), timeStr); | |||||
| // if (stocksetlock) { | |||||
| // try { | |||||
| // if (!redisLock.hasCouponStockCache(wxCouponCVo.getCouponId())) { | |||||
| // redisLock.setCouponStock(wxCouponCVo.getCouponId(), coupon.getRemainInventory()); | |||||
| // } | |||||
| // }catch(Exception e) { | |||||
| // logger.error("save order stock cache error.",e); | |||||
| // }finally { | |||||
| // redisLock.unlock("couponLockStockSetByOrder_"+coupon.getId(), timeStr); | |||||
| // } | |||||
| // }else { | |||||
| // redisLock.unlock("couponLockStockSetByOrder_"+coupon.getId(), timeStr); | |||||
| // } | |||||
| // } | |||||
| // | |||||
| // resultData = couponUserCheck(wxCUserBasicInfo, wxCouponCVo); | |||||
| // if (resultData != null) return resultData; | |||||
| // | |||||
| // Long couponId = orderSaveDto.getCouponId() == null ? wxCouponChannel.getCouponId() : orderSaveDto.getCouponId(); | |||||
| // if (couponId == null) { | |||||
| // logger.error("couponChannelId或者couponId不能为空"); | |||||
| // return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "couponChannelId或者couponId不能为空"); | |||||
| // } | |||||
| // // 是否砍价 | |||||
| // boolean isPress = orderSaveDto.getPress() != null ? orderSaveDto.getPress() : false; | |||||
| // | |||||
| // try { | |||||
| // WxOrder order = wxOrderService.saveOrderForCoupon(wxCUserBasicInfo, coupon, orderSaveDto, isPress,payWay); | |||||
| // return new ResultData(order); | |||||
| // } catch (MallinkException e) { | |||||
| // logger.error(e.getMessage()); | |||||
| // return new ResultData(e.getErrorCode(), e.getMessage()); | |||||
| // } catch (Exception e) { | |||||
| // logger.error(e.getMessage()); | |||||
| // return new ResultData(ErrorCode.ORDER_IS_FAIL, e.getMessage()); | |||||
| // } | |||||
| // } | |||||
| private ResultData couponUserCheck(WxCUserBasicInfo user, WxCouponCVo coupon) { | |||||
| if (coupon.getConditions() == null) return null; | |||||
| JSONObject jo = null; | |||||
| try { | |||||
| jo = JSONObject.parseObject(coupon.getConditions()); | |||||
| } catch (Exception e) { | |||||
| logger.error("购买券条件判断错误:ID=" + coupon.getId() + e.getMessage()); | |||||
| } | |||||
| if (jo != null) { | |||||
| if (jo.getIntValue("type") == EnumCouponConditionType.NEW_MEMBER.getCode()){ | |||||
| if (user != null && user.getActRecord() > 0) | |||||
| return new ResultData(ErrorCode.COUPON_ONLY_FOR_NEW_MEMBER); | |||||
| if (wxOrderService.countCouponConditionType1(coupon.getTenantId(),user.getId()) > 0) | |||||
| return new ResultData(ErrorCode.COUPON_ALREADY_IN_NEW_MEMBER); | |||||
| }else if (jo.getIntValue("type") == EnumCouponConditionType.SCORE_SCOPE.getCode()){ | |||||
| int max = jo.getIntValue("max"); | |||||
| int min = jo.getIntValue("min"); | |||||
| if (max!=0 && min ==0 && user.getPoins() > max) { | |||||
| return new ResultData(ErrorCode.COUPON_SCORE_NOT_IN_RANGE); | |||||
| } | |||||
| if (max==0 && min !=0 && user.getPoins() < min) { | |||||
| return new ResultData(ErrorCode.COUPON_SCORE_NOT_IN_RANGE); | |||||
| } | |||||
| if (max!=0 && min !=0 && (user.getPoins() < min || user.getPoins() > max)) { | |||||
| return new ResultData(ErrorCode.COUPON_SCORE_NOT_IN_RANGE); | |||||
| } | |||||
| } | |||||
| } | |||||
| return null; | |||||
| } | |||||
| private ResultData couponChannelCheck(@RequestBody OrderSaveDto orderSaveDto, WxCouponChannel wxCouponChannel) { | |||||
| if (wxCouponChannel.getTargetAd().equals(EnumCouponChannelType.COUPON_CHANNEL_ID_TIMED.getCode())) { | |||||
| Date now = new Date(); | |||||
| if (wxCouponChannel.getBeginTime().getTime() > now.getTime()) { | |||||
| logger.error("此券活动未开始:" + orderSaveDto.getCouponChannelId()); | |||||
| return new ResultData(ErrorCode.COUPON_CHANNEL_IS_NOT_STARTED); | |||||
| } | |||||
| if (wxCouponChannel.getEndTime().getTime() < now.getTime()) { | |||||
| logger.error("此券活动已结束:" + orderSaveDto.getCouponChannelId()); | |||||
| return new ResultData(ErrorCode.COUPON_CHANNEL_IS_END); | |||||
| } | |||||
| } | |||||
| if (wxCouponChannel.getStatus() == EnumCouponChannelStatus.STATUS_TAKE_OFFF.getCode()) { | |||||
| logger.error("此券已下架:" + orderSaveDto.getCouponChannelId()); | |||||
| return new ResultData(ErrorCode.COUPON_CHANNEL_IS_TAKE_OFF); | |||||
| } | |||||
| return null; | |||||
| } | |||||
| // private ResultData couponUserCheck(WxCUserBasicInfo user, WxCouponCVo coupon) { | |||||
| // if (coupon.getConditions() == null) return null; | |||||
| // JSONObject jo = null; | |||||
| // try { | |||||
| // jo = JSONObject.parseObject(coupon.getConditions()); | |||||
| // } catch (Exception e) { | |||||
| // logger.error("购买券条件判断错误:ID=" + coupon.getId() + e.getMessage()); | |||||
| // } | |||||
| // if (jo != null) { | |||||
| // if (jo.getIntValue("type") == EnumCouponConditionType.NEW_MEMBER.getCode()){ | |||||
| // | |||||
| // if (user != null && user.getActRecord() > 0) | |||||
| // return new ResultData(ErrorCode.COUPON_ONLY_FOR_NEW_MEMBER); | |||||
| // if (wxOrderService.countCouponConditionType1(coupon.getTenantId(),user.getId()) > 0) | |||||
| // return new ResultData(ErrorCode.COUPON_ALREADY_IN_NEW_MEMBER); | |||||
| // }else if (jo.getIntValue("type") == EnumCouponConditionType.SCORE_SCOPE.getCode()){ | |||||
| // int max = jo.getIntValue("max"); | |||||
| // int min = jo.getIntValue("min"); | |||||
| // | |||||
| // if (max!=0 && min ==0 && user.getPoins() > max) { | |||||
| // return new ResultData(ErrorCode.COUPON_SCORE_NOT_IN_RANGE); | |||||
| // } | |||||
| // if (max==0 && min !=0 && user.getPoins() < min) { | |||||
| // return new ResultData(ErrorCode.COUPON_SCORE_NOT_IN_RANGE); | |||||
| // } | |||||
| // if (max!=0 && min !=0 && (user.getPoins() < min || user.getPoins() > max)) { | |||||
| // return new ResultData(ErrorCode.COUPON_SCORE_NOT_IN_RANGE); | |||||
| // } | |||||
| // } | |||||
| // } | |||||
| // | |||||
| // return null; | |||||
| // } | |||||
| // private ResultData couponChannelCheck(@RequestBody OrderSaveDto orderSaveDto, WxCouponChannel wxCouponChannel) { | |||||
| // if (wxCouponChannel.getTargetAd().equals(EnumCouponChannelType.COUPON_CHANNEL_ID_TIMED.getCode())) { | |||||
| // Date now = new Date(); | |||||
| // if (wxCouponChannel.getBeginTime().getTime() > now.getTime()) { | |||||
| // logger.error("此券活动未开始:" + orderSaveDto.getCouponChannelId()); | |||||
| // return new ResultData(ErrorCode.COUPON_CHANNEL_IS_NOT_STARTED); | |||||
| // } | |||||
| // if (wxCouponChannel.getEndTime().getTime() < now.getTime()) { | |||||
| // logger.error("此券活动已结束:" + orderSaveDto.getCouponChannelId()); | |||||
| // return new ResultData(ErrorCode.COUPON_CHANNEL_IS_END); | |||||
| // } | |||||
| // } | |||||
| // | |||||
| // if (wxCouponChannel.getStatus() == EnumCouponChannelStatus.STATUS_TAKE_OFFF.getCode()) { | |||||
| // logger.error("此券已下架:" + orderSaveDto.getCouponChannelId()); | |||||
| // return new ResultData(ErrorCode.COUPON_CHANNEL_IS_TAKE_OFF); | |||||
| // } | |||||
| // return null; | |||||
| // } | |||||
| @ApiOperation(value = "取消订单", notes = "{\"orderId\":\"string\"}") | @ApiOperation(value = "取消订单", notes = "{\"orderId\":\"string\"}") | ||||
| @PostMapping("cancel") | @PostMapping("cancel") | ||||
| @@ -171,6 +171,12 @@ public enum ErrorCode{ | |||||
| * 游戏 | * 游戏 | ||||
| */ | */ | ||||
| GAME_NOT_FOUND(2070, "游戏未找到"), | GAME_NOT_FOUND(2070, "游戏未找到"), | ||||
| GAME_NOT_COUNT(2071, "该游戏未设置免费次数"), | |||||
| GAME_NOT_C_COUNT(2072, "该游戏未设置积分规则"), | |||||
| GAME_NOT_WIN_COUNT(2073, "该游戏您已中过奖"), | |||||
| GAME_NOT_HAVE_COUNT(2074, "您已没有免费次数"), | |||||
| GAME_HAVE_COUNT(2075, "您还有免费次数"), | |||||
| GAME_NOT_HAVEC_COUNT(2076, "您已没有积分次数"), | |||||
| /** | /** | ||||
| * 订单 | * 订单 | ||||
| @@ -46,6 +46,10 @@ public class WxGame extends TenantEntity { | |||||
| @io.swagger.annotations.ApiModelProperty(value = "限奖次数(0:不受限制,n:限奖次数)", name = "awardLimit") | @io.swagger.annotations.ApiModelProperty(value = "限奖次数(0:不受限制,n:限奖次数)", name = "awardLimit") | ||||
| private Integer awardLimit; | private Integer awardLimit; | ||||
| @io.swagger.annotations.ApiModelProperty(value = "次数规则0:总次数 1:每天", name = "limitType") | |||||
| private Integer limitType; | |||||
| @TableField(exist = false) | @TableField(exist = false) | ||||
| @io.swagger.annotations.ApiModelProperty(value = "已投放券信息") | @io.swagger.annotations.ApiModelProperty(value = "已投放券信息") | ||||
| protected List<Object> couponIdsList; // couponChannel | protected List<Object> couponIdsList; // couponChannel | ||||
| @@ -33,8 +33,14 @@ public class WxGameActionLog extends TenantEntity { | |||||
| @io.swagger.annotations.ApiModelProperty(value="",name="createTime") | @io.swagger.annotations.ApiModelProperty(value="",name="createTime") | ||||
| private Date createTime; | private Date createTime; | ||||
| @io.swagger.annotations.ApiModelProperty(value = "", name = "type") | |||||
| @io.swagger.annotations.ApiModelProperty(value = "0:免费玩1:积分玩", name = "type") | |||||
| private Integer type; | private Integer type; | ||||
| @io.swagger.annotations.ApiModelProperty(value = "", name = "usedCredit") | |||||
| private Integer usedCredit; | |||||
| @io.swagger.annotations.ApiModelProperty(value = "", name = "usedCredit") | |||||
| private Integer addCredit; | |||||
| } | } | ||||
| @@ -59,10 +59,7 @@ public interface WxGameService { | |||||
| void deleteById(Long id); | void deleteById(Long id); | ||||
| ResultData luckDraw(Long gameId, Long userId,Integer userCredit); | |||||
| ResultData cridetLuckDraw(Long gameIdL, Long memberId); | |||||
| } | } | ||||
| @@ -239,4 +239,6 @@ public interface WxOrderService { | |||||
| int countUserCouponGroupOrder(Long cuserId,Long couponId,String tenantId); | int countUserCouponGroupOrder(Long cuserId,Long couponId,String tenantId); | ||||
| ResultData saveOrder(OrderSaveDto orderSaveDto,Long cUserId,EnumPayWay payWay,TenantEntity tenantEntity); | |||||
| } | } | ||||
| @@ -8,16 +8,14 @@ import com.github.pagehelper.PageHelper; | |||||
| import com.github.pagehelper.PageInfo; | import com.github.pagehelper.PageInfo; | ||||
| import com.iformall.common.ErrorCode; | import com.iformall.common.ErrorCode; | ||||
| import com.iformall.common.IdWorker; | import com.iformall.common.IdWorker; | ||||
| import com.iformall.common.Result; | |||||
| import com.iformall.common.ResultData; | import com.iformall.common.ResultData; | ||||
| import com.iformall.domain.dto.OrderSaveDto; | |||||
| import com.iformall.domain.po.*; | import com.iformall.domain.po.*; | ||||
| import com.iformall.domain.po.base.TenantEntity; | import com.iformall.domain.po.base.TenantEntity; | ||||
| import com.iformall.domain.vo.WxCouponCVo; | import com.iformall.domain.vo.WxCouponCVo; | ||||
| import com.iformall.domain.vo.WxCouponChannelVo; | import com.iformall.domain.vo.WxCouponChannelVo; | ||||
| import com.iformall.enums.EnumCouponChannelStatus; | |||||
| import com.iformall.enums.EnumCouponChannelType; | |||||
| import com.iformall.enums.EnumCouponStatus; | |||||
| import com.iformall.enums.EnumGameStatus; | |||||
| import com.iformall.enums.EnumPayWay; | |||||
| import com.iformall.enums.*; | |||||
| import com.iformall.exception.MallinkException; | import com.iformall.exception.MallinkException; | ||||
| import com.iformall.mapper.WxCouponChannelMapper; | import com.iformall.mapper.WxCouponChannelMapper; | ||||
| import com.iformall.mapper.WxCouponOrderMapper; | import com.iformall.mapper.WxCouponOrderMapper; | ||||
| @@ -38,10 +36,15 @@ import org.springframework.transaction.annotation.Transactional; | |||||
| import java.util.*; | import java.util.*; | ||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||
| import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW; | |||||
| @Service | @Service | ||||
| public class WxGameServiceImpl implements WxGameService { | public class WxGameServiceImpl implements WxGameService { | ||||
| private final Logger logger = LoggerFactory.getLogger(this.getClass()); | private final Logger logger = LoggerFactory.getLogger(this.getClass()); | ||||
| @Autowired | |||||
| private WxCreditHistoryService wxCreditHistoryService; | |||||
| @Autowired | @Autowired | ||||
| WxGameMapper wxGameMapper; | WxGameMapper wxGameMapper; | ||||
| @@ -66,6 +69,9 @@ public class WxGameServiceImpl implements WxGameService { | |||||
| @Autowired | @Autowired | ||||
| private QrCodeService qrCodeService; | private QrCodeService qrCodeService; | ||||
| @Autowired | |||||
| private WxOrderService wxOrderService; | |||||
| @Autowired | @Autowired | ||||
| @Qualifier("couponDetailRedisTemplate") | @Qualifier("couponDetailRedisTemplate") | ||||
| RedisTemplate<String, WxCouponCVo> cdRedisTemplate; | RedisTemplate<String, WxCouponCVo> cdRedisTemplate; | ||||
| @@ -149,7 +155,20 @@ public class WxGameServiceImpl implements WxGameService { | |||||
| if (wxGame == null) | if (wxGame == null) | ||||
| return new ResultData(ErrorCode.GAME_NOT_FOUND); | return new ResultData(ErrorCode.GAME_NOT_FOUND); | ||||
| WxGameActionLog wxGameActionLog = new WxGameActionLog(); | WxGameActionLog wxGameActionLog = new WxGameActionLog(); | ||||
| if(wxGame.getLimitType().equals(1)){//每天 | |||||
| Calendar calendar = Calendar.getInstance(); | |||||
| calendar.setTime(new Date()); | |||||
| calendar.set(Calendar.HOUR_OF_DAY, 0); | |||||
| calendar.set(Calendar.MINUTE, 0); | |||||
| calendar.set(Calendar.SECOND, 0); | |||||
| Date today = calendar.getTime(); | |||||
| calendar.add(Calendar.DAY_OF_MONTH,1); | |||||
| Date tomorrow =calendar.getTime(); | |||||
| wxGameActionLog.setStartTime(today); | |||||
| wxGameActionLog.setEndTime(tomorrow); | |||||
| } | |||||
| wxGameActionLog.updateTenantInfo(wxGame); | wxGameActionLog.updateTenantInfo(wxGame); | ||||
| wxGameActionLog.setUserId(userId); | wxGameActionLog.setUserId(userId); | ||||
| wxGameActionLog.setGameId(gameId); | wxGameActionLog.setGameId(gameId); | ||||
| @@ -171,12 +190,10 @@ public class WxGameServiceImpl implements WxGameService { | |||||
| Map<String,Object> map = new HashMap(); | Map<String,Object> map = new HashMap(); | ||||
| map.put("playLimit",playLimit);//免费次数限制(为0是不限制次数,为-1是不能玩) | map.put("playLimit",playLimit);//免费次数限制(为0是不限制次数,为-1是不能玩) | ||||
| map.put("playCreditLimit",playCreditLimit);//消耗积分次数限制(为0是不限制次数,为-1是不能玩) | map.put("playCreditLimit",playCreditLimit);//消耗积分次数限制(为0是不限制次数,为-1是不能玩) | ||||
| if(playCreditLimit >= 0){ | |||||
| map.put("playCredit",playCredit);//消耗积分数量 | |||||
| } | |||||
| map.put("playCredit",playCredit);//消耗积分数量 | |||||
| map.put("AwardLimit",AwardLimit);//中奖次数限制(为0是不限制次数) | map.put("AwardLimit",AwardLimit);//中奖次数限制(为0是不限制次数) | ||||
| map.put("playCount",playCount);//当前玩的免费次数 | |||||
| map.put("playCreditCount",playCreditCount);//当前玩的消耗积分次数 | |||||
| map.put("playCount",playCount);//当前玩的免费de次数 | |||||
| map.put("playCreditCount",playCreditCount);//当前玩的消耗积分de次数 | |||||
| map.put("AwardCount",AwardCount);//当前中奖次数 | map.put("AwardCount",AwardCount);//当前中奖次数 | ||||
| boolean playAble = true; | boolean playAble = true; | ||||
| @@ -190,7 +207,6 @@ public class WxGameServiceImpl implements WxGameService { | |||||
| } | } | ||||
| map.put("playAble",playAble); | map.put("playAble",playAble); | ||||
| logger.info(map.toString()); | |||||
| return new ResultData(map); | return new ResultData(map); | ||||
| } | } | ||||
| @@ -217,21 +233,32 @@ public class WxGameServiceImpl implements WxGameService { | |||||
| ValueOperations<String, WxCouponCVo> operations = cdRedisTemplate.opsForValue(); | ValueOperations<String, WxCouponCVo> operations = cdRedisTemplate.opsForValue(); | ||||
| for(int i=0; i<couponChannelIds.size();i++) { | for(int i=0; i<couponChannelIds.size();i++) { | ||||
| JSONObject couponChanObj = (JSONObject) couponChannelIds.get(i); | JSONObject couponChanObj = (JSONObject) couponChannelIds.get(i); | ||||
| Long couponId = couponChanObj.getLong("couponId"); | |||||
| WxCouponChannelVo couponChannelVo = wxCouponChannelsMap.get(couponId); | |||||
| if (couponChannelVo != null) { | |||||
| couponChannelVo.setGameWeight(couponChanObj.getInteger("weight")); | |||||
| couponIdsList.add(couponChannelVo); | |||||
| String key = "cc:" + couponChannelVo.getId(); | |||||
| if (!cdRedisTemplate.hasKey(key)) { | |||||
| WxCouponCVo couponCVo = wxCouponChannelService.findVoStatusDetail(couponChannelVo.getId(),couponChannelQ.getTenantId()); | |||||
| if(Objects.nonNull(couponCVo)) { | |||||
| // 插入缓存 | |||||
| operations.set(key, couponCVo, 3600, TimeUnit.SECONDS); | |||||
| Integer type = couponChanObj.getInteger("prizeType"); | |||||
| if(type != null && type == 0){ | |||||
| Map<String,Object> map = new HashMap<>(); | |||||
| map.put("prizeType",0); | |||||
| map.put("gameWeight",couponChanObj.getInteger("weight")); | |||||
| map.put("credit",couponChanObj.getInteger("credit")); | |||||
| map.put("couponId",couponChanObj.getLong("couponId")); | |||||
| couponIdsList.add(map); | |||||
| }else{ | |||||
| Long couponId = couponChanObj.getLong("couponId"); | |||||
| WxCouponChannelVo couponChannelVo = wxCouponChannelsMap.get(couponId); | |||||
| if (couponChannelVo != null) { | |||||
| couponChannelVo.setGameWeight(couponChanObj.getInteger("weight")); | |||||
| couponIdsList.add(couponChannelVo); | |||||
| String key = "cc:" + couponChannelVo.getId(); | |||||
| if (!cdRedisTemplate.hasKey(key)) { | |||||
| WxCouponCVo couponCVo = wxCouponChannelService.findVoStatusDetail(couponChannelVo.getId(),couponChannelQ.getTenantId()); | |||||
| if(Objects.nonNull(couponCVo)) { | |||||
| // 插入缓存 | |||||
| operations.set(key, couponCVo, 3600, TimeUnit.SECONDS); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return couponIdsList; | return couponIdsList; | ||||
| @@ -382,4 +409,114 @@ public class WxGameServiceImpl implements WxGameService { | |||||
| public void deleteById(Long id) { | public void deleteById(Long id) { | ||||
| wxGameMapper.deleteById(id); | wxGameMapper.deleteById(id); | ||||
| } | } | ||||
| @Transactional(rollbackFor = Exception.class) | |||||
| @Override | |||||
| public ResultData luckDraw(Long gameId,Long userId,Integer userCredit){ | |||||
| ResultData resultData = new ResultData(); | |||||
| WxGame wxGame = this.getById(gameId); | |||||
| List<Object> couponIdsList = wxGame.getCouponIdsList(); | |||||
| int x = (int)(Math.random()*100+1); | |||||
| int y = 0; | |||||
| if(couponIdsList != null || couponIdsList.size() > 0){ | |||||
| for (Object a:couponIdsList) { | |||||
| int weight = 0; | |||||
| if(a instanceof Map){ | |||||
| Map map = (Map) a; | |||||
| weight = (int) map.get("gameWeight"); | |||||
| }else if(a instanceof WxCouponChannelVo){ | |||||
| WxCouponChannelVo vo = (WxCouponChannelVo) a; | |||||
| weight = vo.getGameWeight(); | |||||
| } | |||||
| y += weight; | |||||
| if(x <= y){ | |||||
| resultData.data = a; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| Object data = resultData.data; | |||||
| Long orderId = 0L; | |||||
| Integer addCredit = 0; | |||||
| if(data != null){ | |||||
| if(data instanceof Map){ | |||||
| Map dataMap = (Map) data; | |||||
| // Integer prizeType = (Integer) dataMap.get("prizeType"); | |||||
| // if(prizeType != null && prizeType == 0){ | |||||
| Integer credit = (Integer) dataMap.get("credit"); | |||||
| if(credit > 0){ | |||||
| WxCreditHistory wxCreditHistory = new WxCreditHistory(); | |||||
| wxCreditHistory.setTenantId(wxGame.getFinalTenantId()); | |||||
| wxCreditHistory.setCUserId(userId); | |||||
| wxCreditHistory.setOperatorId(userId); | |||||
| wxCreditHistory.setOperatorType(EnumUserType.CUSER.getCode()); | |||||
| wxCreditHistory.setCreditNum(credit); | |||||
| wxCreditHistory.setCreditType(EnumScoreType.GAME_ADD_CREDIT.getCode()); | |||||
| wxCreditHistory.setChangePurpose(EnumScoreType.GAME_ADD_CREDIT.getMessage()); | |||||
| wxCreditHistoryService.creditUsercheck(wxCreditHistory.getCUserId(),wxGame) ; | |||||
| wxCreditHistoryService.saveOrUpdate(wxCreditHistory); | |||||
| addCredit = credit; | |||||
| orderId = -1L; | |||||
| } | |||||
| resultData.data = null; | |||||
| // } | |||||
| }else if(data instanceof WxCouponChannelVo){ | |||||
| WxCouponChannelVo vo = (WxCouponChannelVo) data; | |||||
| OrderSaveDto orderSaveDto = new OrderSaveDto(); | |||||
| orderSaveDto.setCouponChannelId(vo.getId()); | |||||
| orderSaveDto.setCouponId(vo.getCouponId()); | |||||
| ResultData resultData1 = wxOrderService.saveOrder(orderSaveDto, userId, EnumPayWay.PAY_WAY_WECHAT, wxGame); | |||||
| if(resultData1.code == Result.SUCCESS && resultData1.data != null && resultData1.data instanceof WxOrder){ | |||||
| WxOrder order = (WxOrder)resultData1.data; | |||||
| orderId = order.getId(); | |||||
| }else{ | |||||
| resultData.data = null; | |||||
| } | |||||
| } | |||||
| } | |||||
| final IdWorker idWorker = IdWorker.get(); | |||||
| WxGameActionLog wxGameActionLog = new WxGameActionLog(); | |||||
| wxGameActionLog.setId(idWorker.nextId()); | |||||
| wxGameActionLog.setUserId(userId); | |||||
| wxGameActionLog.updateTenantInfo(wxGame); | |||||
| wxGameActionLog.setGameId(gameId); | |||||
| wxGameActionLog.setCreateTime(new Date()); | |||||
| wxGameActionLog.setUsedCredit(userCredit); | |||||
| if(userCredit > 0){ | |||||
| wxGameActionLog.setType(1); | |||||
| } | |||||
| wxGameActionLog.setCouponOrderId(orderId); | |||||
| wxGameActionLog.setAddCredit(addCredit); | |||||
| wxGameActionLogMapper.insert(wxGameActionLog); | |||||
| return resultData; | |||||
| } | |||||
| @Transactional(propagation = REQUIRES_NEW ,rollbackFor = Exception.class) | |||||
| @Override | |||||
| public ResultData cridetLuckDraw(Long gameId, Long userId) { | |||||
| WxGame wxGame = wxGameMapper.selectById(gameId); | |||||
| if(wxGame.getPlayCredit() != null && wxGame.getPlayCredit() > 0){ | |||||
| WxCreditHistory wxCreditHistory = new WxCreditHistory(); | |||||
| wxCreditHistory.setTenantId(wxGame.getFinalTenantId()); | |||||
| wxCreditHistory.setCUserId(userId); | |||||
| wxCreditHistory.setOperatorId(userId); | |||||
| wxCreditHistory.setOperatorType(EnumUserType.CUSER.getCode()); | |||||
| wxCreditHistory.setCreditNum(wxGame.getPlayCredit()); | |||||
| wxCreditHistory.setCreditType(EnumScoreType.GAME_LES_CREDIT.getCode()); | |||||
| wxCreditHistory.setChangePurpose(EnumScoreType.GAME_LES_CREDIT.getMessage()); | |||||
| wxCreditHistoryService.creditUsercheck(wxCreditHistory.getCUserId(),wxGame) ; | |||||
| WxCreditHistory credit = wxCreditHistoryService.saveOrUpdate(wxCreditHistory); | |||||
| return this.luckDraw(gameId,userId,wxGame.getPlayCredit()); | |||||
| }else{ | |||||
| return new ResultData(ErrorCode.GAME_NOT_C_COUNT); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -16,12 +16,16 @@ import java.util.stream.Collectors; | |||||
| import javax.servlet.http.HttpServletRequest; | import javax.servlet.http.HttpServletRequest; | ||||
| import javax.servlet.http.HttpServletResponse; | import javax.servlet.http.HttpServletResponse; | ||||
| import com.iformall.domain.vo.*; | |||||
| import com.iformall.enums.*; | |||||
| import com.iformall.service.*; | |||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.beans.factory.annotation.Qualifier; | import org.springframework.beans.factory.annotation.Qualifier; | ||||
| import org.springframework.data.redis.core.RedisTemplate; | import org.springframework.data.redis.core.RedisTemplate; | ||||
| import org.springframework.data.redis.core.ValueOperations; | |||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Propagation; | import org.springframework.transaction.annotation.Propagation; | ||||
| import org.springframework.transaction.annotation.Transactional; | import org.springframework.transaction.annotation.Transactional; | ||||
| @@ -56,43 +60,6 @@ import com.iformall.domain.po.WxPayAccount; | |||||
| import com.iformall.domain.po.WxPayOrder; | import com.iformall.domain.po.WxPayOrder; | ||||
| import com.iformall.domain.po.base.TenantEntity; | import com.iformall.domain.po.base.TenantEntity; | ||||
| import com.iformall.domain.po.msg.FmInsideOrderSuccessMsg; | import com.iformall.domain.po.msg.FmInsideOrderSuccessMsg; | ||||
| import com.iformall.domain.vo.WxCouponSendVo; | |||||
| import com.iformall.domain.vo.WxMerchantVo; | |||||
| import com.iformall.domain.vo.WxOrderCouponPressVo; | |||||
| import com.iformall.domain.vo.WxOrderCouponVo; | |||||
| import com.iformall.domain.vo.WxOrderPayExpVo; | |||||
| import com.iformall.domain.vo.WxOrderPayVo; | |||||
| import com.iformall.domain.vo.WxOrderQueryVo; | |||||
| import com.iformall.enums.EnumAssignTagsTrigger; | |||||
| import com.iformall.enums.EnumCacheKey; | |||||
| import com.iformall.enums.EnumCouponChannelStatus; | |||||
| import com.iformall.enums.EnumCouponConditionType; | |||||
| import com.iformall.enums.EnumCouponMerchantStatus; | |||||
| import com.iformall.enums.EnumCouponOrderStatus; | |||||
| import com.iformall.enums.EnumCouponPasswordStatus; | |||||
| import com.iformall.enums.EnumCouponPasswordSupport; | |||||
| import com.iformall.enums.EnumCouponSendSendType; | |||||
| import com.iformall.enums.EnumCouponSendType; | |||||
| import com.iformall.enums.EnumCouponStatus; | |||||
| import com.iformall.enums.EnumCouponTransfer; | |||||
| import com.iformall.enums.EnumCouponType; | |||||
| import com.iformall.enums.EnumMerchantStatus; | |||||
| import com.iformall.enums.EnumMerchantType; | |||||
| import com.iformall.enums.EnumMsgMqKey; | |||||
| import com.iformall.enums.EnumMsgMqTag; | |||||
| import com.iformall.enums.EnumMsgMqTopic; | |||||
| import com.iformall.enums.EnumMsgRecordType; | |||||
| import com.iformall.enums.EnumOrderPressType; | |||||
| import com.iformall.enums.EnumOrderStatus; | |||||
| import com.iformall.enums.EnumOrderType; | |||||
| import com.iformall.enums.EnumPayShare; | |||||
| import com.iformall.enums.EnumPayStatus; | |||||
| import com.iformall.enums.EnumPayType; | |||||
| import com.iformall.enums.EnumPayWay; | |||||
| import com.iformall.enums.EnumProfitSharingOrderType; | |||||
| import com.iformall.enums.EnumScoreType; | |||||
| import com.iformall.enums.EnumUserType; | |||||
| import com.iformall.enums.EnumValidStatus; | |||||
| import com.iformall.exception.MallinkException; | import com.iformall.exception.MallinkException; | ||||
| import com.iformall.mapper.WxAppinfoMapper; | import com.iformall.mapper.WxAppinfoMapper; | ||||
| import com.iformall.mapper.WxCUserBasicInfoMapper; | import com.iformall.mapper.WxCUserBasicInfoMapper; | ||||
| @@ -112,25 +79,13 @@ import com.iformall.mapper.WxOrderPressMapper; | |||||
| import com.iformall.mapper.WxPayAccountMapper; | import com.iformall.mapper.WxPayAccountMapper; | ||||
| import com.iformall.mapper.WxPayOrderMapper; | import com.iformall.mapper.WxPayOrderMapper; | ||||
| import com.iformall.mq.MqBaseProducer; | import com.iformall.mq.MqBaseProducer; | ||||
| import com.iformall.service.ExcelService; | |||||
| import com.iformall.service.WxAppinfoService; | |||||
| import com.iformall.service.WxCUserService; | |||||
| import com.iformall.service.WxCUserTagsService; | |||||
| import com.iformall.service.WxCouponActionLogService; | |||||
| import com.iformall.service.WxCouponSendService; | |||||
| import com.iformall.service.WxCouponService; | |||||
| import com.iformall.service.WxCreditHistoryService; | |||||
| import com.iformall.service.WxMsgLimitService; | |||||
| import com.iformall.service.WxOrderService; | |||||
| import com.iformall.service.WxPayOrderService; | |||||
| import com.iformall.service.WxProfitSharingOrderService; | |||||
| import com.iformall.service.WxScoreRulesService; | |||||
| import com.iformall.utils.Constant; | import com.iformall.utils.Constant; | ||||
| import com.iformall.utils.DateUtils; | import com.iformall.utils.DateUtils; | ||||
| import com.iformall.utils.PayUtils; | import com.iformall.utils.PayUtils; | ||||
| import com.iformall.utils.PressUtils; | import com.iformall.utils.PressUtils; | ||||
| import com.iformall.utils.RedisLock; | import com.iformall.utils.RedisLock; | ||||
| import com.iformall.utils.Utility; | import com.iformall.utils.Utility; | ||||
| import org.springframework.web.bind.annotation.RequestBody; | |||||
| @Service | @Service | ||||
| @@ -168,6 +123,9 @@ public class WxOrderServiceImpl implements WxOrderService { | |||||
| @Autowired | @Autowired | ||||
| WxCUserService wxCUserService; | WxCUserService wxCUserService; | ||||
| @Autowired | |||||
| WxCUserBasicInfoService wxCUserBasicInfoService; | |||||
| @Autowired | @Autowired | ||||
| WxPayOrderMapper wxPayOrderMapper; | WxPayOrderMapper wxPayOrderMapper; | ||||
| @@ -231,6 +189,13 @@ public class WxOrderServiceImpl implements WxOrderService { | |||||
| @Autowired | @Autowired | ||||
| WxCouponService wxCouponService; | WxCouponService wxCouponService; | ||||
| @Autowired | |||||
| WxCouponChannelService wxCouponChannelService; | |||||
| @Autowired | |||||
| @Qualifier("couponDetailRedisTemplate") | |||||
| RedisTemplate<String, WxCouponCVo> cdRedisTemplate; | |||||
| @Override | @Override | ||||
| public PageInfo<WxOrder> listAsPage(WxOrder record, Integer pageIndex, Integer pageSize) { | public PageInfo<WxOrder> listAsPage(WxOrder record, Integer pageIndex, Integer pageSize) { | ||||
| return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxOrderMapper.findList(record)); | return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxOrderMapper.findList(record)); | ||||
| @@ -2426,4 +2391,159 @@ public class WxOrderServiceImpl implements WxOrderService { | |||||
| return wxOrderMapper.countList(query); | return wxOrderMapper.countList(query); | ||||
| } | } | ||||
| @Override | |||||
| public ResultData saveOrder(OrderSaveDto orderSaveDto,Long cUserId,EnumPayWay payWay,TenantEntity tenantEntity) { | |||||
| logger.info("OrderSave: " + orderSaveDto); | |||||
| if (orderSaveDto.getCouponChannelId() == null) { | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "couponChannelId不能为空"); | |||||
| } | |||||
| WxCouponChannel wxCouponChannel = wxCouponChannelService.getById(orderSaveDto.getCouponChannelId(),tenantEntity.getTenantId()); | |||||
| if (wxCouponChannel == null) { | |||||
| logger.error("couponChannelId find error, " + orderSaveDto.getCouponChannelId()); | |||||
| return new ResultData(ErrorCode.COUPON_CHANNEL_IS_TAKE_OFF); | |||||
| } | |||||
| ResultData resultData = couponChannelCheck(orderSaveDto, wxCouponChannel); | |||||
| if (resultData != null) return resultData; | |||||
| WxCUserBasicInfo wxCUserBasicInfo = wxCUserBasicInfoService.getById(cUserId,tenantEntity.getFinalTenantId()); | |||||
| if (wxCUserBasicInfo != null && wxCUserBasicInfo.getStatus().equals(EnumCUserBasicInfoStatus.LOCKED.getCode())) { | |||||
| logger.info("会员权益被锁定:cUserId:" + cUserId); | |||||
| return new ResultData(ErrorCode.MEMBER_IS_LOCKED); | |||||
| } | |||||
| WxCoupon coupon = wxCouponService.getById(wxCouponChannel.getCouponId(),wxCouponChannel.getTenantId()); | |||||
| if (null == coupon) { | |||||
| return new ResultData(ErrorCode.COUPON_IS_EMPTY); | |||||
| } | |||||
| if (coupon.getStatus().equals(EnumCouponStatus.COUPON_STATUS_TAKE_OFFF.getCode())) { | |||||
| return new ResultData(ErrorCode.COUPON_IS_TAKE_OFF); | |||||
| } | |||||
| //判断是否是拼团订单,如果是拼团订单,判断现在进行中的,和已完成的数量是否超出券的限制 | |||||
| if (coupon.getType().equals(EnumCouponType.COUPON_GROUP.getCode())) { | |||||
| int ordercount = this.countUserCouponGroupOrder(cUserId,coupon.getId(),coupon.getTenantId()); | |||||
| if (ordercount>=coupon.getUseLimitQuantity()) { | |||||
| return new ResultData(ErrorCode.COUPON_IS_TAKE_OFF.getCode(),"您当前此券的有效拼团数量达到券的限购次数。"); | |||||
| } | |||||
| } | |||||
| WxCouponCVo wxCouponCVo = null; | |||||
| String key = "cc:" + orderSaveDto.getCouponChannelId(); | |||||
| ValueOperations<String, WxCouponCVo> operations = cdRedisTemplate.opsForValue(); | |||||
| // 缓存 | |||||
| boolean hasKey = cdRedisTemplate.hasKey(key); | |||||
| if (hasKey) { | |||||
| // 从缓存获取用户信息 | |||||
| wxCouponCVo = operations.get(key); | |||||
| } else { | |||||
| // 游戏没有入缓存,需要从数据库中读取 | |||||
| wxCouponCVo = wxCouponChannelService.findDetailVo(orderSaveDto.getCouponChannelId(),wxCouponChannel.getTenantId()); | |||||
| if (wxCouponCVo != null) { | |||||
| // 游戏优化,进缓存 | |||||
| cdRedisTemplate.opsForValue().set(key, wxCouponCVo, 3600, TimeUnit.SECONDS); | |||||
| } | |||||
| } | |||||
| if (wxCouponCVo == null) { | |||||
| return new ResultData(ErrorCode.COUPON_IS_EMPTY); | |||||
| } | |||||
| //此处判断是否存在绝对保证库存不超卖的缓存,如果没有,则把当前的库存设置为最大值。如果有,则是后台设置的时候保存的,以那个为准。 | |||||
| boolean hascache = redisLock.hasCouponStockCache(wxCouponCVo.getCouponId()); | |||||
| if (!hascache) { | |||||
| long time = System.currentTimeMillis() + RedisLock.TIMEOUT; | |||||
| String timeStr = String.valueOf(time); | |||||
| boolean stocksetlock = redisLock.lock("couponLockStockSetByOrder_"+coupon.getId(), timeStr); | |||||
| if (stocksetlock) { | |||||
| try { | |||||
| if (!redisLock.hasCouponStockCache(wxCouponCVo.getCouponId())) { | |||||
| redisLock.setCouponStock(wxCouponCVo.getCouponId(), coupon.getRemainInventory()); | |||||
| } | |||||
| }catch(Exception e) { | |||||
| logger.error("save order stock cache error.",e); | |||||
| }finally { | |||||
| redisLock.unlock("couponLockStockSetByOrder_"+coupon.getId(), timeStr); | |||||
| } | |||||
| }else { | |||||
| redisLock.unlock("couponLockStockSetByOrder_"+coupon.getId(), timeStr); | |||||
| } | |||||
| } | |||||
| resultData = couponUserCheck(wxCUserBasicInfo, wxCouponCVo); | |||||
| if (resultData != null) return resultData; | |||||
| Long couponId = orderSaveDto.getCouponId() == null ? wxCouponChannel.getCouponId() : orderSaveDto.getCouponId(); | |||||
| if (couponId == null) { | |||||
| logger.error("couponChannelId或者couponId不能为空"); | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "couponChannelId或者couponId不能为空"); | |||||
| } | |||||
| // 是否砍价 | |||||
| boolean isPress = orderSaveDto.getPress() != null ? orderSaveDto.getPress() : false; | |||||
| try { | |||||
| WxOrder order = this.saveOrderForCoupon(wxCUserBasicInfo, coupon, orderSaveDto, isPress,payWay); | |||||
| return new ResultData(order); | |||||
| } catch (MallinkException e) { | |||||
| logger.error(e.getMessage()); | |||||
| return new ResultData(e.getErrorCode(), e.getMessage()); | |||||
| } catch (Exception e) { | |||||
| logger.error(e.getMessage()); | |||||
| return new ResultData(ErrorCode.ORDER_IS_FAIL, e.getMessage()); | |||||
| } | |||||
| } | |||||
| private ResultData couponChannelCheck(OrderSaveDto orderSaveDto, WxCouponChannel wxCouponChannel) { | |||||
| if (wxCouponChannel.getTargetAd().equals(EnumCouponChannelType.COUPON_CHANNEL_ID_TIMED.getCode())) { | |||||
| Date now = new Date(); | |||||
| if (wxCouponChannel.getBeginTime().getTime() > now.getTime()) { | |||||
| logger.error("此券活动未开始:" + orderSaveDto.getCouponChannelId()); | |||||
| return new ResultData(ErrorCode.COUPON_CHANNEL_IS_NOT_STARTED); | |||||
| } | |||||
| if (wxCouponChannel.getEndTime().getTime() < now.getTime()) { | |||||
| logger.error("此券活动已结束:" + orderSaveDto.getCouponChannelId()); | |||||
| return new ResultData(ErrorCode.COUPON_CHANNEL_IS_END); | |||||
| } | |||||
| } | |||||
| if (wxCouponChannel.getStatus() == EnumCouponChannelStatus.STATUS_TAKE_OFFF.getCode()) { | |||||
| logger.error("此券已下架:" + orderSaveDto.getCouponChannelId()); | |||||
| return new ResultData(ErrorCode.COUPON_CHANNEL_IS_TAKE_OFF); | |||||
| } | |||||
| return null; | |||||
| } | |||||
| private ResultData couponUserCheck(WxCUserBasicInfo user, WxCouponCVo coupon) { | |||||
| if (coupon.getConditions() == null) return null; | |||||
| JSONObject jo = null; | |||||
| try { | |||||
| jo = JSONObject.parseObject(coupon.getConditions()); | |||||
| } catch (Exception e) { | |||||
| logger.error("购买券条件判断错误:ID=" + coupon.getId() + e.getMessage()); | |||||
| } | |||||
| if (jo != null) { | |||||
| if (jo.getIntValue("type") == EnumCouponConditionType.NEW_MEMBER.getCode()){ | |||||
| if (user != null && user.getActRecord() > 0) | |||||
| return new ResultData(ErrorCode.COUPON_ONLY_FOR_NEW_MEMBER); | |||||
| if (this.countCouponConditionType1(coupon.getTenantId(),user.getId()) > 0) | |||||
| return new ResultData(ErrorCode.COUPON_ALREADY_IN_NEW_MEMBER); | |||||
| }else if (jo.getIntValue("type") == EnumCouponConditionType.SCORE_SCOPE.getCode()){ | |||||
| int max = jo.getIntValue("max"); | |||||
| int min = jo.getIntValue("min"); | |||||
| if (max!=0 && min ==0 && user.getPoins() > max) { | |||||
| return new ResultData(ErrorCode.COUPON_SCORE_NOT_IN_RANGE); | |||||
| } | |||||
| if (max==0 && min !=0 && user.getPoins() < min) { | |||||
| return new ResultData(ErrorCode.COUPON_SCORE_NOT_IN_RANGE); | |||||
| } | |||||
| if (max!=0 && min !=0 && (user.getPoins() < min || user.getPoins() > max)) { | |||||
| return new ResultData(ErrorCode.COUPON_SCORE_NOT_IN_RANGE); | |||||
| } | |||||
| } | |||||
| } | |||||
| return null; | |||||
| } | |||||
| } | } | ||||
| @@ -11,10 +11,12 @@ | |||||
| <result column="create_time" jdbcType="TIMESTAMP" property="createTime" /> | <result column="create_time" jdbcType="TIMESTAMP" property="createTime" /> | ||||
| <result column="type" jdbcType="INTEGER" property="type" /> | <result column="type" jdbcType="INTEGER" property="type" /> | ||||
| <result column="used_credit" jdbcType="INTEGER" property="usedCredit" /> | |||||
| <result column="add_credit" jdbcType="INTEGER" property="addCredit" /> | |||||
| </resultMap> | </resultMap> | ||||
| <sql id="allColumns"> | <sql id="allColumns"> | ||||
| `id`,`tenant_id`,`parent_tenant_id`,`coupon_id`,`coupon_order_id`,`channel_type`,`channel_id`,`create_time`,`type` | |||||
| `id`,`tenant_id`,`parent_tenant_id`,`coupon_id`,`coupon_order_id`,`channel_type`,`channel_id`,`create_time`,`type`,`used_credit`,`add_credit` | |||||
| </sql> | </sql> | ||||
| <sql id="dynamicWhereConditions"> | <sql id="dynamicWhereConditions"> | ||||
| @@ -114,18 +116,13 @@ | |||||
| </if> | </if> | ||||
| <if test=" null != createTime "> | |||||
| and `create_time` = #{createTime} | |||||
| </if> | |||||
| <if test=" null != startTime "> | <if test=" null != startTime "> | ||||
| and `start_time` >= #{startTime} | |||||
| and `create_time` >= #{startTime} | |||||
| </if> | </if> | ||||
| <if test=" null != endTime "> | <if test=" null != endTime "> | ||||
| and `end_time` <= #{endTime} | |||||
| and `create_time` <= #{endTime} | |||||
| </if> | </if> | ||||
| <if test=" null != type "> | <if test=" null != type "> | ||||
| @@ -16,10 +16,11 @@ | |||||
| <result column="play_credit_limit" jdbcType="INTEGER" property="playCreditLimit" /> | <result column="play_credit_limit" jdbcType="INTEGER" property="playCreditLimit" /> | ||||
| <result column="play_credit" jdbcType="INTEGER" property="playCredit" /> | <result column="play_credit" jdbcType="INTEGER" property="playCredit" /> | ||||
| <result column="limit_type" jdbcType="INTEGER" property="limitType" /> | |||||
| </resultMap> | </resultMap> | ||||
| <sql id="allColumns"> | <sql id="allColumns"> | ||||
| `id`,`tenant_id`,`parent_tenant_id`,`game_id`,`status`,`coupon_ids`,`valid_start_date`,`valid_end_date`,`triggle_action`,`play_limit`,`award_limit`,`play_credit_limit`,`play_credit` | |||||
| `id`,`tenant_id`,`parent_tenant_id`,`game_id`,`status`,`coupon_ids`,`valid_start_date`,`valid_end_date`,`triggle_action`,`play_limit`,`award_limit`,`play_credit_limit`,`play_credit`,`limit_type` | |||||
| </sql> | </sql> | ||||
| <sql id="dynamicWhereConditions"> | <sql id="dynamicWhereConditions"> | ||||