diff --git a/accompany-base/accompany-core/src/main/java/com/accompany/core/enumeration/BillObjTypeEnum.java b/accompany-base/accompany-core/src/main/java/com/accompany/core/enumeration/BillObjTypeEnum.java index b042cfd5e..a6b66dd98 100644 --- a/accompany-base/accompany-core/src/main/java/com/accompany/core/enumeration/BillObjTypeEnum.java +++ b/accompany-base/accompany-core/src/main/java/com/accompany/core/enumeration/BillObjTypeEnum.java @@ -275,6 +275,9 @@ public enum BillObjTypeEnum { LUCKY_GIFT_INCOME_ALLOT( 182, "幸运礼物价值分成", BillTypeEnum.IN, CurrencyEnum.GUILD_CRYSTAL, BillDomainTypeEnum.GUILD_POLICY2), NORMAL_GIFT_INCOME_ALLOT( 183, "普通礼物价值分成", BillTypeEnum.IN, CurrencyEnum.GUILD_CRYSTAL, BillDomainTypeEnum.GUILD_POLICY2), GUILD_POLICY2_CRYSTAL_SETTLEMENT( 184, "公会紫晶结算", BillTypeEnum.OUT, CurrencyEnum.GUILD_CRYSTAL, BillDomainTypeEnum.GUILD_POLICY2), + + EXCHANGE_GUILD_CRYSTAL_TO_DIAMOND_PAY( 185, "公会紫晶兑换金币支出", BillTypeEnum.OUT, CurrencyEnum.GUILD_CRYSTAL, BillDomainTypeEnum.EXCHANGE), + EXCHANGE_GUILD_CRYSTAL_TO_DIAMOND_INCOME( 186, "公会紫晶兑换金币收入", BillTypeEnum.IN, CurrencyEnum.DIAMOND, BillDomainTypeEnum.EXCHANGE), ; BillObjTypeEnum(int value, String desc, BillTypeEnum type, CurrencyEnum currency, BillDomainTypeEnum domain) { diff --git a/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/vo/guildpolicy/GuildCrystalExchangeConfigVo.java b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/vo/guildpolicy/GuildCrystalExchangeConfigVo.java new file mode 100644 index 000000000..92747e496 --- /dev/null +++ b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/vo/guildpolicy/GuildCrystalExchangeConfigVo.java @@ -0,0 +1,25 @@ +package com.accompany.business.vo.guildpolicy; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +@ApiModel +@Data +public class GuildCrystalExchangeConfigVo { + + @ApiModelProperty("uid") + private Long uid; + @ApiModelProperty("公会紫晶余额") + private Double guildCrystalNum; + @ApiModelProperty("比例") + private BigDecimal rate; + + @ApiModelProperty("最小兑换紫晶数量") + private Long minCrystalNumLimit; + @ApiModelProperty("允许兑换倍数最小单位") + private Long multipleUnit; + +} diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/UserPurseMapper.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/UserPurseMapper.java index 2a8807e1d..cf728ce13 100644 --- a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/UserPurseMapper.java +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/UserPurseMapper.java @@ -48,6 +48,8 @@ public interface UserPurseMapper extends BaseMapper { int updateSettlementGuildCrystal(@Param("uid") Long uid, @Param("guildCrystal") Double guildCrystal); + int excGuildCrystalToDiamond(@Param("uid") Long uid, @Param("excNum") Double excNum, @Param("diamondNum") Double diamondNum); + UserPurse queryByUid(@Param("uid") Long uid); } \ No newline at end of file diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/guildpolicy2/GuildCrystalExchangeService.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/guildpolicy2/GuildCrystalExchangeService.java new file mode 100644 index 000000000..5de8cb50c --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/guildpolicy2/GuildCrystalExchangeService.java @@ -0,0 +1,98 @@ +package com.accompany.business.service.guildpolicy2; + +import com.accompany.business.model.UserPurse; +import com.accompany.business.model.guild.GuildMember; +import com.accompany.business.service.guild.GuildMemberService; +import com.accompany.business.service.purse.UserPurseService; +import com.accompany.business.service.user.UsersService; +import com.accompany.business.vo.guildpolicy.GuildCrystalExchangeConfigVo; +import com.accompany.common.constant.Constant; +import com.accompany.common.status.BusiStatus; +import com.accompany.core.enumeration.PartitionEnum; +import com.accompany.core.exception.ServiceException; +import com.accompany.core.model.Users; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import java.math.BigDecimal; + +@Slf4j +@Service +public class GuildCrystalExchangeService { + + @Autowired + @Lazy + private UserPurseService userPurseService; + @Autowired + private UsersService usersService; + @Autowired + private GuildMemberService guildMemberService; + + private final BigDecimal RATE = BigDecimal.ONE; + private final long EXCHANGE_LIMIT = 1000L; + + public GuildCrystalExchangeConfigVo buildVo(Long uid){ + Users u = usersService.getNotNullUsersByUid(uid); + PartitionEnum partitionEnum = PartitionEnum.getByPartitionId(u.getPartitionId()); + + if (!Constant.ClanMode.GUILD_POLICY2.equals(partitionEnum.getClanMode())){ + throw new ServiceException(BusiStatus.PARTITION_ERROR); + } + + GuildMember guildMember = guildMemberService.getVaildGuildMemberByUid(uid); + if (guildMember == null){ + throw new ServiceException(BusiStatus.PARTITION_ERROR); + } + + UserPurse userPurse = userPurseService.queryUserPurse(uid); + + GuildCrystalExchangeConfigVo vo = new GuildCrystalExchangeConfigVo(); + vo.setUid(uid); + vo.setGuildCrystalNum(userPurse.getGuildCrystal()); + vo.setRate(RATE); + vo.setMinCrystalNumLimit(EXCHANGE_LIMIT); + vo.setMultipleUnit(EXCHANGE_LIMIT); + + return vo; + } + + public void exchange(Long uid, Long guildCrystalNum) { + if (null == guildCrystalNum || guildCrystalNum <= 0L){ + throw new ServiceException(BusiStatus.PARAMERROR); + } + + if (guildCrystalNum < EXCHANGE_LIMIT || guildCrystalNum % EXCHANGE_LIMIT != 0L){ + throw new ServiceException(BusiStatus.PARAMERROR); + } + + Users u = usersService.getNotNullUsersByUid(uid); + PartitionEnum partitionEnum = PartitionEnum.getByPartitionId(u.getPartitionId()); + + if (!Constant.ClanMode.GUILD_POLICY2.equals(partitionEnum.getClanMode())){ + throw new ServiceException(BusiStatus.PARTITION_ERROR); + } + + GuildMember guildMember = guildMemberService.getVaildGuildMemberByUid(uid); + if (guildMember == null){ + throw new ServiceException(BusiStatus.PARTITION_ERROR); + } + + Double guildCrystalNumD = guildCrystalNum.doubleValue(); + + UserPurse userPurse = userPurseService.queryUserPurse(uid); + Double currentGuildCrystalNum = userPurse.getGuildCrystal(); + if (Double.compare(currentGuildCrystalNum, guildCrystalNumD) < 0){ + log.error("[guild crystal 兑换] {} 钱包 guild crystal 数 {} 少于兑换需要扣 guild crystal 数 {}", uid, currentGuildCrystalNum, guildCrystalNumD); + throw new ServiceException(BusiStatus.PURSE_MONEY_NOT_ENOUGH); + } + + Double diamondD = BigDecimal.valueOf(guildCrystalNum).multiply(RATE).doubleValue(); + userPurseService.excGuildCrystalToDiamond(uid, guildCrystalNumD, diamondD, BusiStatus.PURSE_MONEY_NOT_ENOUGH); + + insertGuildCrystalExchangeRecord(uid, guildMember, guildCrystalNumD, diamondD, RATE); + + log.info("[guild crystal 兑换] {} guild crystal {} 要兑换的金币数 {} 比率 {} 成功", uid, guildCrystalNum, diamondD, RATE); + } + +} diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/purse/UserPurseService.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/purse/UserPurseService.java index 4303493c2..11578e505 100644 --- a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/purse/UserPurseService.java +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/purse/UserPurseService.java @@ -723,4 +723,34 @@ public class UserPurseService extends ServiceImpl { billRecordService.insertGeneralBillRecord(uid, objTypeEnum, guildUsdNum.doubleValue(), after); return after; } + + @Frozen + @Transactional(rollbackFor = Exception.class, transactionManager = "mybatisplusTransactionManager") + public UserPurse excGuildCrystalToDiamond(Long uid, Double guildCrystalNumD, Double diamondD, BusiStatus busiStatus) { + if (guildCrystalNumD <= 0d) { + throw new ServiceException(BusiStatus.AMOUNT_PARAM_ERROR); + } + UserPurse after = withLock(uid, RedisKey.lock_user_guild_crystal, userPurse -> { + double restNum = DoubleUtil.sub(userPurse.getGuildCrystal(), guildCrystalNumD); + if (restNum < 0d){ + throw new ServiceException(busiStatus); + } + //保持操作原子性 + int ret = baseMapper.excGuildCrystalToDiamond(uid, guildCrystalNumD, diamondD); + boolean result = SqlHelper.retBool(ret); + if(!result) { + throw new ServiceException(BusiStatus.SERVERBUSY); + } + userPurse.setGuildCrystal(restNum); + userPurse.setDiamonds(DoubleUtil.add(userPurse.getDiamonds(), diamondD)); + userPurse.setUpdateTime(new Date()); + log.info("excGuildCrystalToDiamond,uid:{}, exchangeNum:{},result:{}",uid, guildCrystalNumD, result); + return userPurse; + }); + + billRecordService.insertGeneralBillRecord(uid, BillObjTypeEnum.EXCHANGE_CRYSTAL_TO_DIAMOND_PAY, guildCrystalNumD, after); + billRecordService.insertGeneralBillRecord(uid, BillObjTypeEnum.EXCHANGE_CRYSTAL_TO_DIAMOND_INCOME, diamondD, after); + + return after; + } } diff --git a/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/UserPurseMapper.xml b/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/UserPurseMapper.xml index 745635b59..bbb300815 100644 --- a/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/UserPurseMapper.xml +++ b/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/UserPurseMapper.xml @@ -104,4 +104,9 @@ where uid=#{uid} + + update user_purse set guild_crystal = guild_crystal - #{excNum},diamonds = diamonds + #{diamondNum}, update_time=now() + where uid=#{uid} and guild_crystal >= #{excNum} + + \ No newline at end of file diff --git a/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/guildpolicy/GuildCrystalExchangeController.java b/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/guildpolicy/GuildCrystalExchangeController.java new file mode 100644 index 000000000..09e200138 --- /dev/null +++ b/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/guildpolicy/GuildCrystalExchangeController.java @@ -0,0 +1,59 @@ +package com.accompany.business.controller.guildpolicy; + +import com.accompany.business.common.BaseController; +import com.accompany.business.service.guildpolicy2.GuildCrystalExchangeService; +import com.accompany.business.vo.guildpolicy.GuildCrystalExchangeConfigVo; +import com.accompany.common.annotation.Authorization; +import com.accompany.common.annotation.H5Authorization; +import com.accompany.common.result.BusiResult; +import com.accompany.common.status.BusiStatus; +import com.accompany.core.exception.ServiceException; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +@Api(tags = "公会紫晶兑换", value = "公会紫晶兑换") +@RestController +@RequestMapping("/guild/guildCrystalExchange") +public class GuildCrystalExchangeController extends BaseController { + + @Autowired + private GuildCrystalExchangeService service; + + @Authorization + @H5Authorization + @ApiOperation("获取配置") + @GetMapping(value = "/getConfig") + public BusiResult getConfig(HttpServletRequest request) { + Long uid = getUid(request); + GuildCrystalExchangeConfigVo configVo = service.buildVo(uid); + return new BusiResult<>(configVo); + } + + @Authorization + @H5Authorization + @ApiOperation("兑换") + @ApiImplicitParams({ + @ApiImplicitParam(name = "guildCrystalNum", value = "公会紫晶数量", required = true, dataType = "Long", paramType = "query") + }) + @PostMapping(value = "/exchange") + public BusiResult exchange(HttpServletRequest request, Long guildCrystalNum) { + if (null == guildCrystalNum || guildCrystalNum < 0) { + throw new ServiceException(BusiStatus.PARAMERROR); + } + Long uid = getUid(request); + service.exchange(uid, guildCrystalNum); + return new BusiResult<>(BusiStatus.GOLD_EXCHANGE_DIAMOND_SUCCESS); + } + + + +} diff --git a/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/guildpolicy/GuildPolicy2Controller.java b/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/guildpolicy/GuildPolicy2Controller.java index 2a5f05034..9430fc877 100644 --- a/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/guildpolicy/GuildPolicy2Controller.java +++ b/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/guildpolicy/GuildPolicy2Controller.java @@ -33,7 +33,6 @@ public class GuildPolicy2Controller { @Autowired private GuildMemberRoomMicRecordService guildMemberRoomMicRecordService; - @ApiOperation(value = "公会收入统计", httpMethod = "GET") @ApiImplicitParams({ @ApiImplicitParam(name = "cycleBeginDate", value = "周期开始日期yyyy-MM-dd", required = true, dataType = "String", paramType = "query")