master:系统BUG解决;

pull/1121/head
liujiang 2025-11-06 10:33:16 +08:00
parent ef30d6b279
commit 7b1d0b6cca
14 changed files with 355 additions and 31 deletions

View File

@ -37,14 +37,6 @@ public class StoreController extends XktBaseController {
final ISysUserService userService;
final TokenService tokenService;
// TODO 获取试用期即将到期的档口
// TODO 获取试用期即将到期的档口
// TODO 获取获取正式使用即将到期的档口
// TODO 获取获取正式使用即将到期的档口
@PreAuthorize("@ss.hasAnyRoles('admin,general_admin,store')||@ss.hasSupplierSubRole()")
@ApiOperation(value = "模糊查询档口", httpMethod = "GET", response = R.class)
@Log(title = "模糊查询档口", businessType = BusinessType.UPDATE)
@ -105,7 +97,6 @@ public class StoreController extends XktBaseController {
return R.ok(BeanUtil.toBean(storeService.getExpireInfo(storeId), StoreExpireResVO.class));
}
@ApiOperation(value = "PC 商城首页 获取档口基础信息", httpMethod = "GET", response = R.class)
@GetMapping(value = "/simple/{storeId}")
public R<StoreSimpleResVO> getSimpleInfo(@PathVariable("storeId") Long storeId) {
@ -202,4 +193,26 @@ public class StoreController extends XktBaseController {
return R.ok(storeService.getStockSys(storeId));
}
@PreAuthorize("@ss.hasAnyRoles('admin,general_admin,store')||@ss.hasSupplierSubRole()")
@Log(title = "档口购买正式版", businessType = BusinessType.INSERT)
@PostMapping(value = "/annual")
public R<Integer> buyAnnual(@Validated @RequestBody StoreBuyAnnualVO buyAnnualVO) {
return R.ok(storeService.buyAnnual(BeanUtil.toBean(buyAnnualVO, StoreBuyAnnualDTO.class)));
}
@PreAuthorize("@ss.hasAnyRoles('admin')")
@Log(title = "档口购买正式版no money", businessType = BusinessType.INSERT)
@PostMapping(value = "/annual/no-money/{storeId}")
public R<Integer> buyAnnualWithOutMoney(@PathVariable Long storeId) {
return R.ok(storeService.buyAnnualWithOutMoney(storeId));
}
@PreAuthorize("@ss.hasAnyRoles('admin')")
@Log(title = "更新试用期、年费优惠价、会员优惠价", businessType = BusinessType.INSERT)
@PutMapping(value = "/special")
public R<Integer> UpdateSpecialAttr(@Validated @RequestBody StoreUpdateSpecialVO specialVO) {
return R.ok(storeService.UpdateSpecialAttr(BeanUtil.toBean(specialVO, StoreUpdateSpecialDTO.class)));
}
}

View File

@ -6,9 +6,7 @@ import com.ruoyi.common.core.controller.XktBaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.web.controller.xkt.vo.storeFactory.StoreFactoryResVO;
import com.ruoyi.web.controller.xkt.vo.storeMember.StoreMemberCreateVO;
import com.ruoyi.web.controller.xkt.vo.storeMember.StoreMemberExpireResVO;
import com.ruoyi.web.controller.xkt.vo.storeMember.StoreMemberPageVO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberCreateDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberPageDTO;
@ -21,8 +19,6 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* controller
*
@ -45,6 +41,13 @@ public class StoreMemberController extends XktBaseController {
return R.ok(storeMemberService.create(BeanUtil.toBean(createVO, StoreMemberCreateDTO.class)));
}
@PreAuthorize("@ss.hasAnyRoles('admin')")
@Log(title = "新增档口会员no money", businessType = BusinessType.INSERT)
@PostMapping("/no-money/{storeId}")
public R<Integer> createNoMoney(@PathVariable Long storeId) {
return R.ok(storeMemberService.createNoMoney(storeId));
}
@PreAuthorize("@ss.hasAnyRoles('admin,general_admin')")
@ApiOperation(value = "查询会员列表 ", httpMethod = "POST", response = R.class)
@PostMapping("/page")

View File

@ -0,0 +1,33 @@
package com.ruoyi.web.controller.xkt.vo.store;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel
@Data
@Accessors(chain = true)
public class StoreBuyAnnualVO {
@NotNull(message = "档口ID不能为空!")
@ApiModelProperty(value = "档口ID", required = true)
private Long storeId;
@NotNull(message = "支付金额不能为空!")
@ApiModelProperty(value = "支付金额", required = true)
private BigDecimal payPrice;
@NotNull(message = "支付方式不能为空!")
@ApiModelProperty(value = "支付方式", required = true)
private Integer payWay;
@ApiModelProperty(value = "交易密码")
private String transactionPassword;
}

View File

@ -0,0 +1,32 @@
package com.ruoyi.web.controller.xkt.vo.store;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel
@Data
@Accessors(chain = true)
public class StoreUpdateSpecialVO {
@NotNull(message = "档口ID不能为空")
@ApiModelProperty(value = "档口ID", required = true)
private Long storeId;
@ApiModelProperty(value = "年费金额")
private BigDecimal serviceAmount;
@ApiModelProperty(value = "会员金额")
private BigDecimal memberAmount;
@ApiModelProperty(value = "服务截止时间")
private Date serviceEndTime;
}

View File

@ -267,6 +267,10 @@ public class Constants
// 每个档口默认 现金客户
public static final String STORE_CUS_CASH = "现金客户";
// 年费暂定3999
public static final BigDecimal STORE_ANNUAL_AMOUNT = new BigDecimal(3999);
// 会员费暂定5999
public static final BigDecimal STORE_MEMBER_AMOUNT = new BigDecimal(5999);
/**
*

View File

@ -104,7 +104,14 @@ public class Store extends XktBaseEntity {
*/
@Excel(name = "保证金")
private BigDecimal integrityGold;
/**
*
*/
private BigDecimal serviceAmount;
/**
*
*/
private BigDecimal memberAmount;
/**
* storeStatus=3 storeStatus=4
*/

View File

@ -0,0 +1,29 @@
package com.ruoyi.xkt.dto.store;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel
@Data
@Accessors(chain = true)
public class StoreBuyAnnualDTO {
@ApiModelProperty(value = "档口ID")
private Long storeId;
@ApiModelProperty(value = "支付金额")
private BigDecimal payPrice;
@ApiModelProperty(value = "支付方式")
private Integer payWay;
@ApiModelProperty(value = "交易密码")
private String transactionPassword;
}

View File

@ -0,0 +1,30 @@
package com.ruoyi.xkt.dto.store;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel
@Data
@Accessors(chain = true)
public class StoreUpdateSpecialDTO {
@ApiModelProperty(value = "档口ID")
private Long storeId;
@ApiModelProperty(value = "年费金额")
private BigDecimal serviceAmount;
@ApiModelProperty(value = "会员金额")
private BigDecimal memberAmount;
@ApiModelProperty(value = "服务截止时间")
private Date serviceEndTime;
}

View File

@ -2,7 +2,6 @@ package com.ruoyi.xkt.service;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.xkt.dto.storeMember.StoreMemberCreateDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberExpireResDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberPageDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberPageResDTO;
@ -30,4 +29,12 @@ public interface IStoreMemberService {
*/
Page<StoreMemberPageResDTO> page(StoreMemberPageDTO pageDTO);
/**
*
*
* @param storeId ID
* @return Integer
*/
Integer createNoMoney(Long storeId);
}

View File

@ -199,4 +199,29 @@ public interface IStoreService {
* @return StoreExpireResDTO
*/
StoreExpireResDTO getExpireInfo(Long storeId);
/**
*
*
* @param buyAnnualDTO
* @return Integer
*/
Integer buyAnnual(StoreBuyAnnualDTO buyAnnualDTO);
/**
*
*
* @param storeId ID
* @return Integer
*/
Integer buyAnnualWithOutMoney(Long storeId);
/**
*
*
* @param specialDTO
* @return Integer
*/
Integer UpdateSpecialAttr(StoreUpdateSpecialDTO specialDTO);
}

View File

@ -5,7 +5,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.model.ESystemRole;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
@ -44,7 +43,6 @@ public class StoreCertificateServiceImpl implements IStoreCertificateService {
final StoreCertificateMapper storeCertMapper;
final SysFileMapper fileMapper;
final StoreMapper storeMapper;
final RedisCache redisCache;
final IAssetService assetService;
final StoreSaleDetailMapper saleDetailMapper;
final StoreProductMapper storeProdMapper;

View File

@ -1,6 +1,5 @@
package com.ruoyi.xkt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@ -14,7 +13,6 @@ import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.xkt.domain.Store;
import com.ruoyi.xkt.domain.StoreMember;
import com.ruoyi.xkt.dto.storeMember.StoreMemberCreateDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberExpireResDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberPageDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberPageResDTO;
import com.ruoyi.xkt.enums.*;
@ -116,6 +114,56 @@ public class StoreMemberServiceImpl implements IStoreMemberService {
return count;
}
/**
*
*
* @param storeId ID
* @return Integer
*/
@Override
@Transactional
public Integer createNoMoney(Long storeId) {
// 用户是否为超级管理员
if (!SecurityUtils.isSuperAdmin()) {
throw new ServiceException("当前用户非超级管理员,无权限操作!", HttpStatus.ERROR);
}
// 看是否已存在会员
StoreMember storeMember = this.storeMemberMapper.selectOne(new LambdaQueryWrapper<StoreMember>()
.eq(StoreMember::getStoreId, storeId).eq(StoreMember::getDelFlag, Constants.UNDELETED));
int count;
// 已存在会员,则在之前的基础上续期
if (ObjectUtils.isNotEmpty(storeMember)) {
// 续期结束时间在原来基础上再加一年
Date memberEndTime = storeMember.getEndTime();
// 直接增加一年
Date memberEndTimePlus = Date.from(memberEndTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
.plusYears(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
storeMember.setEndTime(memberEndTimePlus);
storeMember.setUpdateBy(SecurityUtils.getUsername());
count = this.storeMemberMapper.updateById(storeMember);
} else {
storeMember = new StoreMember();
storeMember.setStoreId(storeId);
// 最低等级会员:实力质造
storeMember.setLevel(StoreMemberLevel.STRENGTH_CONSTRUCT.getValue());
storeMember.setStartTime(java.sql.Date.valueOf(LocalDate.now()));
// 过期时间设置为1年后
storeMember.setEndTime(java.sql.Date.valueOf(LocalDate.now().plusYears(1)));
storeMember.setVoucherDate(java.sql.Date.valueOf(LocalDate.now()));
storeMember.setCreateBy(SecurityUtils.getUsername());
count = this.storeMemberMapper.insert(storeMember);
// 将档口权重增加1
Store store = Optional.ofNullable(this.storeMapper.selectOne(new LambdaQueryWrapper<Store>()
.eq(Store::getId, storeId).eq(Store::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("档口不存在!", HttpStatus.ERROR));
store.setStoreWeight(ObjectUtils.defaultIfNull(store.getStoreWeight(), 0) + 1);
this.storeMapper.updateById(store);
// 将档口会员信息添加到 redis 中
redisCache.setCacheObject(CacheConstants.STORE_MEMBER + storeId, storeMember);
}
return count;
}
/**
*
*

View File

@ -13,7 +13,6 @@ import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.ESystemRole;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
@ -27,12 +26,10 @@ import com.ruoyi.xkt.domain.*;
import com.ruoyi.xkt.dto.store.*;
import com.ruoyi.xkt.dto.storeCertificate.StoreCertDTO;
import com.ruoyi.xkt.dto.storeCertificate.StoreCertResDTO;
import com.ruoyi.xkt.enums.FileType;
import com.ruoyi.xkt.enums.SaleType;
import com.ruoyi.xkt.enums.StockSysType;
import com.ruoyi.xkt.enums.StoreStatus;
import com.ruoyi.xkt.enums.*;
import com.ruoyi.xkt.mapper.*;
import com.ruoyi.xkt.service.IAssetService;
import com.ruoyi.xkt.service.INoticeService;
import com.ruoyi.xkt.service.IStoreCertificateService;
import com.ruoyi.xkt.service.IStoreService;
import lombok.RequiredArgsConstructor;
@ -46,6 +43,7 @@ import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
@ -80,6 +78,7 @@ public class StoreServiceImpl implements IStoreService {
final IStoreCertificateService storeCertService;
final EsClientWrapper esClientWrapper;
final StoreMemberMapper storeMemberMapper;
final INoticeService noticeService;
/**
*
@ -440,19 +439,115 @@ public class StoreServiceImpl implements IStoreService {
@Transactional(readOnly = true)
public StoreExpireResDTO getExpireInfo(Long storeId) {
Store store = Optional.ofNullable(storeMapper.selectById(storeId)).orElseThrow(() -> new ServiceException("档口不存在!", HttpStatus.ERROR));
StoreExpireResDTO expireDTO = new StoreExpireResDTO().setStoreId(storeId).setServiceEndTime(store.getServiceEndTime());
StoreExpireResDTO expireDTO = new StoreExpireResDTO().setStoreId(storeId).setServiceEndTime(store.getServiceEndTime())
.setServiceAmount(ObjectUtils.defaultIfNull(store.getServiceAmount(), Constants.STORE_ANNUAL_AMOUNT))
.setMemberAmount(ObjectUtils.defaultIfNull(store.getMemberAmount(), Constants.STORE_MEMBER_AMOUNT));
// 获取档口会员
Date todayStart = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
StoreMember storeMember = this.storeMemberMapper.selectOne(new LambdaQueryWrapper<StoreMember>()
.eq(StoreMember::getStoreId, storeId).eq(StoreMember::getDelFlag, Constants.UNDELETED)
.le(StoreMember::getStartTime, todayStart));
expireDTO.setServiceEndTime(ObjectUtils.isNotEmpty(storeMember) ? storeMember.getEndTime() : null);
return expireDTO.setMemberEndTime(ObjectUtils.isNotEmpty(storeMember) ? storeMember.getEndTime() : null);
}
// TODO 获取购买正式版金额
/**
*
*
* @param buyAnnualDTO
* @return Integer
*/
@Override
@Transactional
public Integer buyAnnual(StoreBuyAnnualDTO buyAnnualDTO) {
// 用户是否为档口管理者或子账户
if (!SecurityUtils.isAdmin() && !SecurityUtils.isStoreManagerOrSub(buyAnnualDTO.getStoreId())) {
throw new ServiceException("当前用户非管理员账号,无权限操作!", HttpStatus.ERROR);
}
//校验推广支付方式是否存在
AdPayWay.of(buyAnnualDTO.getPayWay());
// 校验使用余额情况下,密码是否正确
if (Objects.equals(buyAnnualDTO.getPayWay(), AdPayWay.BALANCE.getValue())
&& !assetService.checkTransactionPassword(buyAnnualDTO.getStoreId(), buyAnnualDTO.getTransactionPassword())) {
throw new ServiceException("支付密码错误!请重新输入", HttpStatus.ERROR);
}
Optional.ofNullable(buyAnnualDTO.getStoreId()).orElseThrow(() -> new RuntimeException("档口ID不能为空!"));
Optional.ofNullable(buyAnnualDTO.getPayPrice()).orElseThrow(() -> new RuntimeException("购买金额不能为空!"));
Store store = Optional.ofNullable(storeMapper.selectById(buyAnnualDTO.getStoreId())).orElseThrow(() -> new ServiceException("档口不存在!", HttpStatus.ERROR));
// 判断扣费金额和折扣金额是否一致(设置了折扣,就用折扣,反之取默认金额)
final BigDecimal serviceAmount = ObjectUtils.defaultIfNull(store.getServiceAmount(), Constants.STORE_ANNUAL_AMOUNT);
if (!Objects.equals(serviceAmount, buyAnnualDTO.getPayPrice())) {
throw new ServiceException("付费金额与核定金额不一致!请联系平台客服", HttpStatus.ERROR);
}
// 年费续费成功之后,就将优惠金额清空,下一年再有优惠就需重新设置
store.setServiceAmount(null);
// 如果是使用版 storeStatus 为3更新为正式版 storeStatus 为4
if (Objects.equals(store.getStoreStatus(), StoreStatus.TRIAL_PERIOD.getValue())) {
store.setStoreStatus(StoreStatus.FORMAL_USE.getValue());
}
// 更新服务到期时间 在原服务时间基础上 往后推 1年
store.setServiceEndTime(Date.from(store.getServiceEndTime().toInstant().plus(1, ChronoUnit.YEARS)));
int count = this.storeMapper.updateById(store);
// 更新redis 中的 store信息
this.redisCache.setCacheObject(CacheConstants.STORE_KEY + store.getId(), store);
// 新增续缴年费成功的消息通知
this.noticeService.createSingleNotice(SecurityUtils.getUserId(), "年费续缴成功!", NoticeType.NOTICE.getValue(), NoticeOwnerType.SYSTEM.getValue(),
buyAnnualDTO.getStoreId(), UserNoticeType.SYSTEM_MSG.getValue(), "恭喜您!年费续缴成功!");
// 扣除会员费
assetService.payVipFee(buyAnnualDTO.getStoreId(), buyAnnualDTO.getPayPrice());
return count;
}
// TODO 获取购买会员金额
/**
*
*
* @param storeId ID
* @return Integer
*/
@Override
@Transactional
public Integer buyAnnualWithOutMoney(Long storeId) {
// 用户是否为超级管理员
if (!SecurityUtils.isSuperAdmin()) {
throw new ServiceException("当前用户非超级管理员,无权限操作!", HttpStatus.ERROR);
}
Store store = Optional.ofNullable(storeMapper.selectById(storeId)).orElseThrow(() -> new ServiceException("档口不存在!", HttpStatus.ERROR));
// 年费续费成功之后,就将优惠金额清空,下一年再有优惠就需重新设置
store.setServiceAmount(null);
// 如果是使用版 storeStatus 为3更新为正式版 storeStatus 为4
if (Objects.equals(store.getStoreStatus(), StoreStatus.TRIAL_PERIOD.getValue())) {
store.setStoreStatus(StoreStatus.FORMAL_USE.getValue());
}
// 更新服务到期时间 在原服务时间基础上 往后推 1年
store.setServiceEndTime(Date.from(store.getServiceEndTime().toInstant().plus(1, ChronoUnit.YEARS)));
// 更新redis 中的 store信息
this.redisCache.setCacheObject(CacheConstants.STORE_KEY + store.getId(), store);
return this.storeMapper.updateById(store);
}
return expireDTO;
/**
*
*
* @param specialDTO
* @return Integer
*/
@Override
@Transactional
public Integer UpdateSpecialAttr(StoreUpdateSpecialDTO specialDTO) {
// 用户是否为超级管理员
if (!SecurityUtils.isSuperAdmin()) {
throw new ServiceException("当前用户非超级管理员,无权限操作!", HttpStatus.ERROR);
}
Store store = Optional.ofNullable(storeMapper.selectById(specialDTO.getStoreId())).orElseThrow(() -> new ServiceException("档口不存在!", HttpStatus.ERROR));
if (ObjectUtils.isNotEmpty(specialDTO.getServiceEndTime())) {
store.setServiceEndTime(specialDTO.getServiceEndTime());
}
if (ObjectUtils.isNotEmpty(specialDTO.getServiceAmount())) {
store.setServiceAmount(specialDTO.getServiceAmount());
}
if (ObjectUtils.isNotEmpty(specialDTO.getMemberAmount())) {
store.setMemberAmount(specialDTO.getMemberAmount());
}
return this.storeMapper.updateById(store);
}

View File

@ -5,7 +5,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<mapper namespace="com.ruoyi.xkt.mapper.StoreSaleDetailMapper">
<select id="selectRefundByBuJuSnSale" resultType="com.ruoyi.xkt.dto.storeProdColorSize.StoreSaleSnResDTO">
SELECT
SELECT DISTINCT
ssd.store_prod_id,
ssd.store_prod_color_id,
ssd.store_cus_name,
@ -34,7 +34,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectRefundByOtherSnSale" resultType="com.ruoyi.xkt.dto.storeProdColorSize.StoreSaleSnResDTO">
SELECT
SELECT DISTINCT
ssd.store_prod_id,
ssd.store_prod_color_id,
ssd.store_cus_name,