Merge #111 into master from cc_20260417_bonus

fix:工资奖金

* cc_20260417_bonus: (28 commits squashed)

  - feat:工资奖金发放

  - fix:工资奖金发放

  - fix:工资奖金发放

  - fix:工资奖金发放

  - fix:工资奖金发放

  - fix:门店实收相关接口

  - fix:新品销售门店级接口

  - fix:新品销售菜品列表接口;规则新增返回id

  - fix:新品销售菜品详情接口

  - fix:新品销售菜品接口补充

  - fix:小程序接口补充

  - fix

  - fix:新增实收、新品销售测试接口

  - fix:新增实收、新品销售测试接口

  - fix

  - fix:新增门店菜品列表接口

  - fix:同规则下无法新增相同菜品规则;新增小程序门店列表接口

  - fix

  - fix:小程序用户获取来源修改

  - fix:实收规则新增上月日均实收字段

  - fix:规则限制

  - fix:小程序上月日均实收

  - fix:查询异常

  - fix:查询异常

  - fix:菜品员工明细字段赋值异常

  - fix:排序

  - fix:排序

  - fix:员工实收列表新增门店筛选条件

Signed-off-by: 王非凡 <accounts_67eba0c5fee9c49c80c8e2b4@mail.teambition.com>
Merged-by: 正新 <accounts_6964c7bcd2a2c377c5bbd01b@mail.teambition.com>

CR-link: https://codeup.aliyun.com/692ea314dec569489f6f167c/hangzhou/java/custom_zxjp/change/111
This commit is contained in:
王非凡
2026-04-27 10:41:08 +00:00
committed by 正新
parent 97f8a8669c
commit 22fcfc6a90
95 changed files with 5466 additions and 8 deletions

View File

@@ -493,6 +493,13 @@ public enum ErrorCodeEnum {
CLOSE_UP_CLOSED_AUDIT_NOT_PASS(1840008, "歇业申请未通过", null),
CLOSE_UP_EXIST_OPEN_APPLY(1840009, "该歇业申请单已存在开业申请", null),
CLOSE_UP_APPROVED(1840010, "该申请单已审批", null),
BONUS_EXIST_OVERLAP_RULE(1850000, "门店该有效期范围内存在相同类型的启用规则", null),
BONUS_RULE_NOT_EXIST(1850001, "不存在该奖金发放规则", null),
BONUS_RULE_NOT_CONFIG(1850002, "奖金规则或分配规则未配置", null),
BONUS_DISTRIBUTE_RATIO_OVER_100(1850003, "分配规则员工比例之和大于100", null),
BONUS_PRODUCT_CONFIG_DUPLICATE(1850004, "奖金规则配置存在重复菜品", null),
BONUS_RULE_CONFIG_ERROR(1850005, "规则配置异常", null),
;

View File

@@ -0,0 +1,78 @@
package com.cool.store.utils;
import java.nio.charset.StandardCharsets;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
/**
* 门店开放数据签名工具类
*
* @author wangff
* @since 2026/4/20
*/
public class StoreOpenSigner {
private static final SecureRandom RANDOM = new SecureRandom();
/**
* 构建签名串
*
* @param method HTTP方法如POST
* @param requestPath 请求路径,如/open/v1/store/monthRevenue
* @param rawJsonBody 原始JSON请求体
* @param signTime 签名时间戳
* @param signRandom 随机串
* @return 签名串
*/
public static String buildSigningString(String method, String requestPath, String rawJsonBody,
String signTime, String signRandom) {
return method + "&" + requestPath + "&" + rawJsonBody + "&" + signTime + "&" + signRandom;
}
/**
* HMAC-SHA256签名返回小写十六进制字符串
*
* @param signingString 签名串
* @param secret 密钥
* @return 签名结果
*/
public static String sign(String signingString, String secret) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] digest = mac.doFinal(signingString.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder(digest.length * 2);
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (Exception e) {
throw new RuntimeException("签名失败", e);
}
}
/**
* 生成随机串
*
* @param length 随机串长度
* @return 随机串
*/
public static String generateRandom(int length) {
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
sb.append(chars.charAt(RANDOM.nextInt(chars.length())));
}
return sb.toString();
}
/**
* 生成签名时间戳(秒)
*
* @return Unix秒时间戳字符串
*/
public static String generateSignTime() {
return String.valueOf(System.currentTimeMillis() / 1000);
}
}

View File

@@ -0,0 +1,61 @@
package com.cool.store.dao.bonus;
import com.cool.store.entity.bonus.BonusDistributionRuleDO;
import com.cool.store.mapper.bonus.BonusDistributionRuleMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import java.util.Date;
import java.util.List;
/**
* <p>
* 奖金发放规则DAO
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Repository
@RequiredArgsConstructor
public class BonusDistributionRuleDAO {
private final BonusDistributionRuleMapper bonusDistributionRuleMapper;
public boolean addRule(BonusDistributionRuleDO ruleDO) {
return bonusDistributionRuleMapper.insertSelective(ruleDO) > 0;
}
/**
* 门店下相同规则类型的启用规则生效期间有无交集
* @param storeId 门店id
* @param type 规则类型
* @param startDate 开始有效日期
* @param endDate 结束有效日期
* @return 是否存在
*/
public boolean existOverlap(String storeId, Integer type, Date startDate, Date endDate) {
return bonusDistributionRuleMapper.existOverlap(storeId, type, startDate, endDate) > 0;
}
public BonusDistributionRuleDO getById(Long id) {
return bonusDistributionRuleMapper.selectByPrimaryKey(id);
}
public boolean updateByPrimaryKeySelective(BonusDistributionRuleDO ruleDO) {
return bonusDistributionRuleMapper.updateByPrimaryKeySelective(ruleDO) > 0;
}
public List<BonusDistributionRuleDO> getList(String storeNumOrName, Integer type, Integer enable, String storeId) {
return bonusDistributionRuleMapper.getList(storeNumOrName, type, enable, storeId);
}
/**
* 获取指定类型和生效月份的启用规则列表
* @param type 规则类型
* @param payMonth 发放月份 yyyy-MM
* @return 规则列表
*/
public List<BonusDistributionRuleDO> getEnabledRulesByTypeAndMonth(Integer type, String payMonth) {
return bonusDistributionRuleMapper.selectEnabledRulesByTypeAndMonth(type, payMonth);
}
}

View File

@@ -0,0 +1,37 @@
package com.cool.store.dao.bonus;
import com.alibaba.excel.util.CollectionUtils;
import com.cool.store.entity.bonus.BonusEmployeeRewardDetailDO;
import com.cool.store.mapper.bonus.BonusEmployeeRewardDetailMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import java.util.Date;
import java.util.List;
/**
* 员工奖励明细DAO
*
* @author wangff
* @since 2026/4/21
*/
@Repository
@RequiredArgsConstructor
public class BonusEmployeeRewardDetailDAO {
private final BonusEmployeeRewardDetailMapper mapper;
public int insert(BonusEmployeeRewardDetailDO entity) {
return mapper.insertSelective(entity);
}
public int insertOrUpdateBatch(List<BonusEmployeeRewardDetailDO> list) {
if (CollectionUtils.isEmpty(list)) {
return 0;
}
return mapper.insertOrUpdateBatch(list);
}
public List<BonusEmployeeRewardDetailDO> selectListByCondition(String storeNumOrName, Date startDate, Date endDate, String rewardUserName, String storeId) {
return mapper.selectListByCondition(storeNumOrName, startDate, endDate, rewardUserName, storeId);
}
}

View File

@@ -0,0 +1,82 @@
package com.cool.store.dao.bonus;
import cn.hutool.core.collection.CollStreamUtil;
import com.cool.store.entity.bonus.BonusNewProductEmployeeDO;
import com.cool.store.mapper.bonus.BonusNewProductEmployeeMapper;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.stereotype.Repository;
import tk.mybatis.mapper.entity.Example;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* 新品销售奖金-员工DAO
*
* @author wangff
* @since 2026/4/21
*/
@Repository
@RequiredArgsConstructor
public class BonusNewProductEmployeeDAO {
private final BonusNewProductEmployeeMapper mapper;
public int insert(BonusNewProductEmployeeDO entity) {
return mapper.insertSelective(entity);
}
public int insertBatch(List<BonusNewProductEmployeeDO> list) {
if (CollectionUtils.isEmpty(list)) {
return 0;
}
return mapper.insertBatch(list);
}
/**
* 月度奖金统计
* @param storeId 门店id
* @param payDate 发放年月
* @param userIds 用户id列表
* @return 实体列表
*/
public Map<String, BigDecimal> getMonthlyStatistics(String storeId, String payDate, List<String> userIds) {
List<Map<String, Objects>> list = mapper.getMonthlyStatistics(storeId, payDate, userIds);
return CollStreamUtil.toMap(list, v -> MapUtils.getString(v, "reward_user_id"), v -> new BigDecimal(MapUtils.getString(v, "total_amount")));
}
/**
* 月度统计
*/
public List<BonusNewProductEmployeeDO> monthlyStatistics(Long ruleId, String storeId, Date payDate, String userId) {
return mapper.monthlyStatistics(ruleId, storeId, payDate, userId);
}
/**
* 员工列表月度统计
*/
public List<BonusNewProductEmployeeDO> employeeMonthlyStatistics(Date startDate,
Date endDate,
String storeNumOrName,
String rewardUserName,
String storeId) {
return mapper.employeeMonthlyStatistics(startDate, endDate, storeNumOrName, rewardUserName, storeId);
}
public List<BonusNewProductEmployeeDO> getMonthlyStatisticsGroupByStore(String payMonth) {
return mapper.getMonthlyStatisticsGroupByStore(payMonth);
}
public void deleteDailyNewProduct(Long ruleId, String storeId, Date payDate) {
Example example = new Example(BonusNewProductEmployeeDO.class);
example.createCriteria()
.andEqualTo("ruleId", ruleId)
.andEqualTo("storeId", storeId)
.andEqualTo("payDate", payDate);
mapper.deleteByExample(example);
}
}

View File

@@ -0,0 +1,64 @@
package com.cool.store.dao.bonus;
import cn.hutool.core.collection.CollStreamUtil;
import com.alibaba.excel.util.CollectionUtils;
import com.cool.store.entity.bonus.BonusNewProductRecipeDO;
import com.cool.store.mapper.bonus.BonusNewProductRecipeMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import tk.mybatis.mapper.entity.Example;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 新品销售奖金-菜品DAO
*
* @author wangff
* @since 2026/4/21
*/
@Repository
@RequiredArgsConstructor
public class BonusNewProductRecipeDAO {
private final BonusNewProductRecipeMapper mapper;
public int insert(BonusNewProductRecipeDO entity) {
return mapper.insertSelective(entity);
}
public int insertBatch(List<BonusNewProductRecipeDO> list) {
if (CollectionUtils.isEmpty(list)) {
return 0;
}
return mapper.insertBatch(list);
}
public List<BonusNewProductRecipeDO> monthlyStatistics(String storeNumOrName, Date startDate, Date endDate, String recipeNoOrName) {
return mapper.monthlyStatistics(storeNumOrName, startDate, endDate, recipeNoOrName);
}
public List<BonusNewProductRecipeDO> selectListByCondition(String storeId, String recipeNo, Date startDate, Date endDate) {
return mapper.selectListByCondition(storeId, recipeNo, startDate, endDate);
}
public Map<Long, BonusNewProductRecipeDO> getMapByIds(List<Long> ids) {
if (CollectionUtils.isEmpty(ids)) {
return Collections.emptyMap();
}
Example example = new Example(BonusNewProductRecipeDO.class);
example.createCriteria().andIn("id", ids);
List<BonusNewProductRecipeDO> list = mapper.selectByExample(example);
return CollStreamUtil.toMap(list, BonusNewProductRecipeDO::getId, v -> v);
}
public void deleteDailyNewProduct(Long ruleId, String storeId, Date payDate) {
Example example = new Example(BonusNewProductRecipeDO.class);
example.createCriteria()
.andEqualTo("ruleId", ruleId)
.andEqualTo("storeId", storeId)
.andEqualTo("payDate", payDate);
mapper.deleteByExample(example);
}
}

View File

@@ -0,0 +1,74 @@
package com.cool.store.dao.bonus;
import com.alibaba.excel.util.CollectionUtils;
import com.cool.store.entity.bonus.BonusNewProductRecipeEmployeeDO;
import com.cool.store.mapper.bonus.BonusNewProductRecipeEmployeeMapper;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository;
import tk.mybatis.mapper.entity.Example;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* 新品销售奖金-菜品-员工DAO
*
* @author wangff
* @since 2026/4/21
*/
@Repository
@RequiredArgsConstructor
public class BonusNewProductRecipeEmployeeDAO {
private final BonusNewProductRecipeEmployeeMapper mapper;
public int insert(BonusNewProductRecipeEmployeeDO entity) {
return mapper.insertSelective(entity);
}
public int insertBatch(List<BonusNewProductRecipeEmployeeDO> list) {
if (CollectionUtils.isEmpty(list)) {
return 0;
}
return mapper.insertBatch(list);
}
/**
* 月度统计
*/
public List<BonusNewProductRecipeEmployeeDO> monthlyStatistics(String storeNumOrName, Date startDate, Date endDate, String rewardUserName, String recipeNoOrName) {
return mapper.monthlyStatistics(storeNumOrName, startDate, endDate, rewardUserName, recipeNoOrName);
}
public List<BonusNewProductRecipeEmployeeDO> selectListByCondition(String storeId, String recipeNo, String rewardUserId, Date startDate, Date endDate) {
Example example = new Example(BonusNewProductRecipeEmployeeDO.class);
Example.Criteria criteria = example.createCriteria();
if (StringUtils.isNotBlank(storeId)) {
criteria.andEqualTo("storeId", storeId);
}
if (StringUtils.isNotBlank(recipeNo)) {
criteria.andEqualTo("recipeNo", recipeNo);
}
if (StringUtils.isNotBlank(rewardUserId)) {
criteria.andEqualTo("rewardUserId", rewardUserId);
}
if (Objects.nonNull(startDate)) {
criteria.andGreaterThanOrEqualTo("payDate", startDate);
}
if (Objects.nonNull(endDate)) {
criteria.andLessThanOrEqualTo("payDate", endDate);
}
example.setOrderByClause("create_time DESC");
return mapper.selectByExample(example);
}
public void deleteDailyNewProduct(Long ruleId, String storeId, Date payDate) {
Example example = new Example(BonusNewProductRecipeEmployeeDO.class);
example.createCriteria()
.andEqualTo("ruleId", ruleId)
.andEqualTo("storeId", storeId)
.andEqualTo("payDate", payDate);
mapper.deleteByExample(example);
}
}

View File

@@ -0,0 +1,51 @@
package com.cool.store.dao.bonus;
import cn.hutool.core.collection.CollStreamUtil;
import com.cool.store.entity.bonus.BonusNewProductStoreDO;
import com.cool.store.mapper.bonus.BonusNewProductStoreMapper;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Repository;
import tk.mybatis.mapper.entity.Example;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 新品销售奖金-门店DAO
*
* @author wangff
* @since 2026/4/21
*/
@Repository
@RequiredArgsConstructor
public class BonusNewProductStoreDAO {
private final BonusNewProductStoreMapper mapper;
public int insert(BonusNewProductStoreDO entity) {
return mapper.insertSelective(entity);
}
public boolean existsByRuleIdAndPayDate(Long ruleId, String payDate) {
return mapper.selectCountByRuleIdAndPayDate(ruleId, payDate) > 0;
}
public BonusNewProductStoreDO getById(Long id) {
return mapper.selectByPrimaryKey(id);
}
public List<BonusNewProductStoreDO> monthlyStatistics(String storeNumOrName, Date startDate, Date endDate, String storeId, Long ruleId) {
return mapper.monthlyStatistics(storeNumOrName, startDate, endDate, storeId, ruleId);
}
public void deleteDailyNewProduct(Long ruleId, String storeId, Date payDate) {
Example example = new Example(BonusNewProductStoreDO.class);
example.createCriteria()
.andEqualTo("ruleId", ruleId)
.andEqualTo("storeId", storeId)
.andEqualTo("payDate", payDate);
mapper.deleteByExample(example);
}
}

View File

@@ -0,0 +1,62 @@
package com.cool.store.dao.bonus;
import com.cool.store.entity.bonus.BonusReceivedEmployeeDO;
import com.cool.store.mapper.bonus.BonusReceivedEmployeeMapper;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Repository;
import tk.mybatis.mapper.entity.Example;
import java.util.Date;
import java.util.List;
/**
* 实收奖金发放-员工DAO
*
* @author wangff
* @since 2026/4/21
*/
@Repository
@RequiredArgsConstructor
public class BonusReceivedEmployeeDAO {
private final BonusReceivedEmployeeMapper mapper;
public int insert(BonusReceivedEmployeeDO entity) {
return mapper.insertSelective(entity);
}
public int insertBatch(List<BonusReceivedEmployeeDO> list) {
if (CollectionUtils.isEmpty(list)) {
return 0;
}
return mapper.insertBatch(list);
}
public List<BonusReceivedEmployeeDO> selectByReceivedStoreId(Long receivedStoreId) {
return mapper.selectByReceivedStoreId(receivedStoreId);
}
public BonusReceivedEmployeeDO getById(Long id) {
return mapper.selectByPrimaryKey(id);
}
public List<BonusReceivedEmployeeDO> selectEmployeeListByCondition(String storeNumOrName, Date startMonth, Date endMonth, String rewardUserName, String storeId) {
return mapper.selectEmployeeListByCondition(storeNumOrName, startMonth, endMonth, rewardUserName, storeId);
}
/**
* 按门店分组统计员工月度实收
*/
public List<BonusReceivedEmployeeDO> getMonthlyStatisticsGroupByStore(String payMonth) {
return mapper.getMonthlyStatisticsGroupByStore(payMonth);
}
public void deleteMonthlyReceived(Long ruleId, String storeId, Date payDate) {
Example example = new Example(BonusReceivedEmployeeDO.class);
example.createCriteria()
.andEqualTo("ruleId", ruleId)
.andEqualTo("storeId", storeId)
.andEqualTo("payDate", payDate);
mapper.deleteByExample(example);
}
}

View File

@@ -0,0 +1,62 @@
package com.cool.store.dao.bonus;
import cn.hutool.core.collection.CollStreamUtil;
import com.cool.store.entity.bonus.BonusReceivedStoreDO;
import com.cool.store.mapper.bonus.BonusReceivedStoreMapper;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Repository;
import tk.mybatis.mapper.entity.Example;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 实收奖金发放-门店DAO
*
* @author wangff
* @since 2026/4/21
*/
@Repository
@RequiredArgsConstructor
public class BonusReceivedStoreDAO {
private final BonusReceivedStoreMapper mapper;
public int insert(BonusReceivedStoreDO entity) {
return mapper.insertSelective(entity);
}
public boolean existsByRuleIdAndPayDate(Long ruleId, String payDate) {
return mapper.selectCountByRuleIdAndPayDate(ruleId, payDate) > 0;
}
public BonusReceivedStoreDO getById(Long id) {
return mapper.selectByPrimaryKey(id);
}
public List<BonusReceivedStoreDO> selectListByCondition(String storeNumOrName, Date startMonth, Date endMonth, String storeId) {
return mapper.selectListByCondition(storeNumOrName, startMonth, endMonth, storeId);
}
public Map<Long, BonusReceivedStoreDO> getMapByIds(List<Long> ids) {
if (CollectionUtils.isEmpty(ids)) {
return Collections.emptyMap();
}
Example example = new Example(BonusReceivedStoreDO.class);
example.createCriteria()
.andIn("id", ids);
List<BonusReceivedStoreDO> list = mapper.selectByExample(example);
return CollStreamUtil.toMap(list, BonusReceivedStoreDO::getId, v -> v);
}
public void deleteMonthlyReceived(Long ruleId, String storeId, Date payDate) {
Example example = new Example(BonusReceivedStoreDO.class);
example.createCriteria()
.andEqualTo("ruleId", ruleId)
.andEqualTo("storeId", storeId)
.andEqualTo("payDate", payDate);
mapper.deleteByExample(example);
}
}

View File

@@ -52,6 +52,14 @@ public interface UserAuthMappingMapper {
@Param("positionType")String positionType,
@Param("notRoleAuth")String notRoleAuth);
/**
* 与标品一致listUserAuthMappingByAuth方法会查询出运营顾问等角色
*/
List<UserAuthMappingDO> listUserAuthMappingByAuthV2(@Param("type") String type,
@Param("mappingIdList") List<String> mappingIdList,
@Param("positionType")String positionType,
@Param("notRoleAuth")String notRoleAuth);
List<UserAuthMappingDO> listUserAuthMappingByUserList(@Param("userIdList") List<String> userIdList);

View File

@@ -0,0 +1,34 @@
package com.cool.store.mapper.bonus;
import com.cool.store.entity.bonus.BonusDistributionRuleDO;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.mapper.common.Mapper;
import java.util.Date;
import java.util.List;
public interface BonusDistributionRuleMapper extends Mapper<BonusDistributionRuleDO> {
/**
* 门店下相同规则类型的启用规则生效期间有无交集
* @param storeId 门店id
* @param type 规则类型
* @param startDate 开始有效日期
* @param endDate 结束有效日期
* @return 是否存在
*/
int existOverlap(@Param("storeId") String storeId, @Param("type") Integer type, @Param("startDate") Date startDate, @Param("endDate") Date endDate);
/**
* 列表查询
*/
List<BonusDistributionRuleDO> getList(@Param("storeNumOrName") String storeNumOrName,
@Param("type") Integer type,
@Param("enable") Integer enable,
@Param("storeId") String storeId);
/**
* 获取指定类型和生效月份的启用规则列表
*/
List<BonusDistributionRuleDO> selectEnabledRulesByTypeAndMonth(@Param("type") Integer type, @Param("payMonth") String payMonth);
}

View File

@@ -0,0 +1,28 @@
package com.cool.store.mapper.bonus;
import com.cool.store.entity.bonus.BonusEmployeeRewardDetailDO;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.mapper.common.Mapper;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
public interface BonusEmployeeRewardDetailMapper extends Mapper<BonusEmployeeRewardDetailDO> {
List<BonusEmployeeRewardDetailDO> selectByStoreIdAndPayDate(@Param("storeId") String storeId,
@Param("payDate") String payDate,
@Param("userIds") List<String> userIds);
int updateReceivedAmountById(@Param("id") Long id, @Param("receivedAmount") BigDecimal receivedAmount);
int updateNewProjectAmountById(@Param("id") Long id, @Param("newProjectAmount") BigDecimal newProjectAmount);
int insertOrUpdateBatch(@Param("list") List<BonusEmployeeRewardDetailDO> list);
List<BonusEmployeeRewardDetailDO> selectListByCondition(@Param("storeNumOrName") String storeNumOrName,
@Param("startDate") Date startDate,
@Param("endDate") Date endDate,
@Param("rewardUserName") String rewardUserName,
@Param("storeId") String storeId);
}

View File

@@ -0,0 +1,46 @@
package com.cool.store.mapper.bonus;
import com.cool.store.entity.bonus.BonusNewProductEmployeeDO;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.mapper.common.Mapper;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public interface BonusNewProductEmployeeMapper extends Mapper<BonusNewProductEmployeeDO> {
/**
* 月度统计
*
* @param storeId 门店id
* @param payDate 发放年月
* @param userIds 用户id列表
* @return 实体列表
*/
List<Map<String, Objects>> getMonthlyStatistics(@Param("storeId") String storeId,
@Param("payDate") String payDate,
@Param("userIds") List<String> userIds);
int insertBatch(@Param("list") List<BonusNewProductEmployeeDO> list);
List<BonusNewProductEmployeeDO> monthlyStatistics(@Param("ruleId") Long ruleId,
@Param("storeId") String storeId,
@Param("payDate") Date payDate,
@Param("userId") String userId);
/**
* 员工列表月度统计
*/
List<BonusNewProductEmployeeDO> employeeMonthlyStatistics(@Param("startDate") Date startDate,
@Param("endDate") Date endDate,
@Param("storeNumOrName") String storeNumOrName,
@Param("rewardUserName") String rewardUserName,
@Param("storeId") String storeId);
/**
* 按门店分组统计员工月度新品销售
*/
List<BonusNewProductEmployeeDO> getMonthlyStatisticsGroupByStore(@Param("payMonth") String payMonth);
}

View File

@@ -0,0 +1,22 @@
package com.cool.store.mapper.bonus;
import com.cool.store.entity.bonus.BonusNewProductRecipeEmployeeDO;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.mapper.common.Mapper;
import java.util.Date;
import java.util.List;
public interface BonusNewProductRecipeEmployeeMapper extends Mapper<BonusNewProductRecipeEmployeeDO> {
int insertBatch(@Param("list") List<BonusNewProductRecipeEmployeeDO> list);
/**
* 月度统计
*/
List<BonusNewProductRecipeEmployeeDO> monthlyStatistics(@Param("storeNumOrName") String storeNumOrName,
@Param("startDate") Date startDate,
@Param("endDate") Date endDate,
@Param("rewardUserName") String rewardUserName,
@Param("recipeNoOrName") String recipeNoOrName);
}

View File

@@ -0,0 +1,23 @@
package com.cool.store.mapper.bonus;
import com.cool.store.entity.bonus.BonusNewProductRecipeDO;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.mapper.common.Mapper;
import java.util.Date;
import java.util.List;
public interface BonusNewProductRecipeMapper extends Mapper<BonusNewProductRecipeDO> {
int insertBatch(@Param("list") List<BonusNewProductRecipeDO> list);
List<BonusNewProductRecipeDO> monthlyStatistics(@Param("storeNumOrName") String storeNumOrName,
@Param("startDate") Date startDate,
@Param("endDate") Date endDate,
@Param("recipeNoOrName") String recipeNoOrName);
List<BonusNewProductRecipeDO> selectListByCondition(@Param("storeId") String storeId,
@Param("recipeNo") String recipeNo,
@Param("startDate") Date startDate,
@Param("endDate") Date endDate);
}

View File

@@ -0,0 +1,20 @@
package com.cool.store.mapper.bonus;
import com.cool.store.entity.bonus.BonusNewProductStoreDO;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.mapper.common.Mapper;
import java.util.Date;
import java.util.List;
public interface BonusNewProductStoreMapper extends Mapper<BonusNewProductStoreDO> {
int selectCountByRuleIdAndPayDate(@Param("ruleId") Long ruleId, @Param("payDate") String payDate);
List<BonusNewProductStoreDO> monthlyStatistics(@Param("storeNumOrName") String storeNumOrName,
@Param("startDate") Date startDate,
@Param("endDate") Date endDate,
@Param("storeId") String storeId,
@Param("ruleId") Long ruleId);
}

View File

@@ -0,0 +1,25 @@
package com.cool.store.mapper.bonus;
import com.cool.store.entity.bonus.BonusReceivedEmployeeDO;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.mapper.common.Mapper;
import java.util.Date;
import java.util.List;
public interface BonusReceivedEmployeeMapper extends Mapper<BonusReceivedEmployeeDO> {
int insertBatch(@Param("list") List<BonusReceivedEmployeeDO> list);
List<BonusReceivedEmployeeDO> selectByReceivedStoreId(@Param("receivedStoreId") Long receivedStoreId);
List<BonusReceivedEmployeeDO> selectEmployeeListByCondition(@Param("storeNumOrName") String storeNumOrName,
@Param("startMonth") Date startMonth,
@Param("endMonth") Date endMonth,
@Param("rewardUserName") String rewardUserName,
@Param("storeId") String storeId);
/**
* 按门店分组统计员工月度实收
*/
List<BonusReceivedEmployeeDO> getMonthlyStatisticsGroupByStore(@Param("payMonth") String payMonth);
}

View File

@@ -0,0 +1,18 @@
package com.cool.store.mapper.bonus;
import com.cool.store.entity.bonus.BonusReceivedStoreDO;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.mapper.common.Mapper;
import java.util.Date;
import java.util.List;
public interface BonusReceivedStoreMapper extends Mapper<BonusReceivedStoreDO> {
int selectCountByRuleIdAndPayDate(@Param("ruleId") Long ruleId, @Param("payDate") String payDate);
List<BonusReceivedStoreDO> selectListByCondition(@Param("storeNumOrName") String storeNumOrName,
@Param("startMonth") Date startMonth,
@Param("endMonth") Date endMonth,
@Param("storeId") String storeId);
}

View File

@@ -67,6 +67,36 @@
</where>
</select>
<select id="listUserAuthMappingByAuthV2" resultMap="baseResult">
select a.id,a.user_id,mapping_id,a.type from user_auth_mapping_${enterpriseId} a
join enterprise_user_${enterpriseId} e on a.user_id= e.user_id
<where>
e.user_status= '1' and e.active= true
<if test="mappingIdList!=null and mappingIdList.size>0">
<foreach collection="mappingIdList" item="mappingId" open="and a.mapping_id in (" separator="," close=")">
#{mappingId}
</foreach>
</if>
<if test="type!=null and type!=''">
and a.type =#{type}
</if>
<if test="(positionType!=null and positionType!='') or (notRoleAuth!=null and notRoleAuth!='')">
and a.user_id in (
select
distinct(user_id)
from enterprise_user_role_${enterpriseId} ur JOIN sys_role_${enterpriseId} b on ur.role_id=b.id
<where>
<if test="positionType!=null and positionType!=''">
and b.position_type =#{positionType}
</if>
<if test="notRoleAuth!=null and notRoleAuth!=''">
and b.role_auth !=#{notRoleAuth}
</if>
</where>
)
</if>
</where>
</select>
<select id="listUserAuthMappingByUserList" resultMap="baseResult">
select * from user_auth_mapping_${enterpriseId}
<where>

View File

@@ -0,0 +1,66 @@
<?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.cool.store.mapper.bonus.BonusDistributionRuleMapper">
<resultMap id="BaseResultMap" type="com.cool.store.entity.bonus.BonusDistributionRuleDO">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="type" jdbcType="BIT" property="type" />
<result column="store_id" jdbcType="VARCHAR" property="storeId" />
<result column="start_date" jdbcType="DATE" property="startDate" />
<result column="end_date" jdbcType="DATE" property="endDate" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="create_user_id" jdbcType="VARCHAR" property="createUserId" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
<result column="update_user_id" jdbcType="VARCHAR" property="updateUserId" />
<result column="bonus_config" jdbcType="LONGVARCHAR" property="bonusConfig" />
<result column="distribute_config" jdbcType="LONGVARCHAR" property="distributeConfig" />
<result column="enable" jdbcType="BIT" property="enable" />
</resultMap>
<sql id="Base_Column_List">
id, type, store_id, start_date, end_date, create_time, create_user_id, update_time, update_user_id, bonus_config, distribute_config, enable
</sql>
<sql id="Base_Column_List_A">
a.id, a.type, a.store_id, a.start_date, a.end_date, a.create_time, a.create_user_id, a.update_time, a.update_user_id, a.bonus_config, a.distribute_config, a.enable
</sql>
<select id="existOverlap" resultType="int">
SELECT COUNT(1) FROM bonus_distribution_rule
WHERE store_id = #{storeId}
AND type = #{type}
AND enable = 1
AND start_date &lt;= #{endDate}
AND end_date >= #{startDate}
</select>
<select id="getList" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List_A" />
FROM bonus_distribution_rule a
<if test="storeNumOrName != null and storeNumOrName != ''">
INNER JOIN store_${enterpriseId} b ON a.store_id = b.store_id AND b.is_delete = 'effective'
</if>
<where>
<if test="storeNumOrName != null and storeNumOrName != ''">
AND (b.store_num LIKE CONCAT('%', #{storeNumOrName}, '%') OR b.store_name LIKE CONCAT('%', #{storeNumOrName}, '%'))
</if>
<if test="type != null">
AND a.type = #{type}
</if>
<if test="enable != null">
AND a.enable = #{enable}
</if>
<if test="storeId != null and storeId != ''">
AND a.store_id = #{storeId}
</if>
</where>
ORDER BY a.create_time DESC
</select>
<select id="selectEnabledRulesByTypeAndMonth" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List" />
FROM bonus_distribution_rule
WHERE type = #{type} AND enable = 1
AND DATE_FORMAT(start_date, '%Y-%m') &lt;= #{payMonth} AND DATE_FORMAT(end_date, '%Y-%m') >= #{payMonth}
</select>
</mapper>

View File

@@ -0,0 +1,78 @@
<?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.cool.store.mapper.bonus.BonusEmployeeRewardDetailMapper">
<resultMap id="BaseResultMap" type="com.cool.store.entity.bonus.BonusEmployeeRewardDetailDO">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="store_id" jdbcType="VARCHAR" property="storeId" />
<result column="pay_date" jdbcType="DATE" property="payDate" />
<result column="reward_user_name" jdbcType="VARCHAR" property="rewardUserName" />
<result column="reward_user_id" jdbcType="VARCHAR" property="rewardUserId" />
<result column="received_amount" jdbcType="DECIMAL" property="receivedAmount" />
<result column="new_project_amount" jdbcType="DECIMAL" property="newProjectAmount" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
</resultMap>
<sql id="Base_Column_List">
id, store_id, pay_date, reward_user_name, reward_user_id, received_amount, new_project_amount, create_time
</sql>
<sql id="Base_Column_List_A">
a.id, a.store_id, a.pay_date, a.reward_user_name, a.reward_user_id, a.received_amount, a.new_project_amount, a.create_time
</sql>
<select id="selectByStoreIdAndPayDate" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List" />
FROM bonus_employee_reward_detail
WHERE store_id = #{storeId}
AND DATE_FORMAT(pay_date, '%Y-%m') = #{payDate}
AND reward_user_id IN
<foreach item="item" index="index" collection="userIds" open="(" separator="," close=")">
#{item}
</foreach>
</select>
<update id="updateReceivedAmountById">
UPDATE bonus_employee_reward_detail SET received_amount = #{receivedAmount} WHERE id = #{id}
</update>
<update id="updateNewProjectAmountById">
UPDATE bonus_employee_reward_detail SET new_project_amount = #{newProjectAmount} WHERE id = #{id}
</update>
<insert id="insertOrUpdateBatch">
INSERT INTO bonus_employee_reward_detail (store_id, pay_date, reward_user_name, reward_user_id, received_amount, new_project_amount) VALUES
<foreach item="item" index="index" collection="list" separator=",">
(#{item.storeId}, #{item.payDate}, #{item.rewardUserName}, #{item.rewardUserId}, #{item.receivedAmount}, #{item.newProjectAmount})
</foreach>
ON DUPLICATE KEY UPDATE
received_amount = VALUES(received_amount),
new_project_amount = VALUES(new_project_amount)
</insert>
<select id="selectListByCondition" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List_A" />
FROM bonus_employee_reward_detail a
<if test="storeNumOrName != null and storeNumOrName != ''">
INNER JOIN store_${enterpriseId} b ON a.store_id = b.store_id AND b.is_delete = 'effective'
</if>
<where>
<if test="storeNumOrName != null and storeNumOrName != ''">
AND (b.store_num LIKE CONCAT('%', #{storeNumOrName}, '%') OR b.store_name LIKE CONCAT('%', #{storeNumOrName}, '%'))
</if>
<if test="startDate != null">
AND a.pay_date >= #{startDate}
</if>
<if test="endDate != null">
AND a.pay_date &lt;= #{endDate}
</if>
<if test="rewardUserName != null and rewardUserName != ''">
AND a.reward_user_name LIKE CONCAT('%', #{rewardUserName}, '%')
</if>
<if test="storeId != null and storeId != ''">
AND a.store_id = #{storeId}
</if>
</where>
</select>
</mapper>

View File

@@ -0,0 +1,96 @@
<?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.cool.store.mapper.bonus.BonusNewProductEmployeeMapper">
<resultMap id="BaseResultMap" type="com.cool.store.entity.bonus.BonusNewProductEmployeeDO">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="product_store_id" jdbcType="BIGINT" property="productStoreId" />
<result column="rule_id" jdbcType="BIGINT" property="ruleId" />
<result column="store_id" jdbcType="VARCHAR" property="storeId" />
<result column="pay_date" jdbcType="DATE" property="payDate" />
<result column="reward_ratio" jdbcType="DECIMAL" property="rewardRatio" />
<result column="reward_amount" jdbcType="DECIMAL" property="rewardAmount" />
<result column="reward_user_name" jdbcType="VARCHAR" property="rewardUserName" />
<result column="reward_user_id" jdbcType="VARCHAR" property="rewardUserId" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
</resultMap>
<select id="getMonthlyStatistics" resultType="java.util.Map">
SELECT reward_user_id, SUM(reward_amount) total_amount
FROM bonus_new_product_employee
WHERE store_id = #{storeId}
AND DATE_FORMAT(pay_date, '%Y-%m') = #{payDate}
AND reward_user_id IN
<foreach item="item" index="index" collection="userIds" open="(" separator="," close=")">
#{item}
</foreach>
GROUP BY reward_user_id
</select>
<insert id="insertBatch" useGeneratedKeys="true" keyProperty="id">
INSERT INTO bonus_new_product_employee (product_store_id, rule_id, store_id, pay_date, reward_ratio, reward_amount, reward_user_name, reward_user_id) VALUES
<foreach item="item" index="index" collection="list" separator=",">
(#{item.productStoreId}, #{item.ruleId}, #{item.storeId}, #{item.payDate}, #{item.rewardRatio}, #{item.rewardAmount}, #{item.rewardUserName}, #{item.rewardUserId})
</foreach>
</insert>
<select id="monthlyStatistics" resultMap="BaseResultMap">
SELECT reward_user_id, reward_user_name, SUM(reward_amount) reward_amount, rule_id
FROM bonus_new_product_employee
<where>
<if test="storeId != null and storeId != ''">
AND store_id = #{storeId}
</if>
<if test="ruleId != null">
AND rule_id = #{ruleId}
</if>
<if test="payDate != null">
AND DATE_FORMAT(pay_date, '%Y-%m') = DATE_FORMAT(#{payDate}, '%Y-%m')
</if>
<if test="userId != null and userId != ''">
AND reward_user_id = #{userId}
</if>
</where>
GROUP BY reward_user_id
</select>
<select id="employeeMonthlyStatistics" resultMap="BaseResultMap">
SELECT a.store_id, a.rule_id, a.reward_user_id, a.reward_user_name, SUM(a.reward_amount) reward_amount, a.pay_date
FROM bonus_new_product_employee a
<if test="storeNumOrName != null and storeNumOrName != ''">
INNER JOIN store_${enterpriseId} b ON a.store_id = b.store_id AND b.is_delete = 'effective'
</if>
<where>
<if test="startDate != null">
AND DATE_FORMAT(a.pay_date, '%Y-%m') >= DATE_FORMAT(#{startDate}, '%Y-%m')
</if>
<if test="endDate != null">
AND DATE_FORMAT(a.pay_date, '%Y-%m') &lt;= DATE_FORMAT(#{endDate}, '%Y-%m')
</if>
<if test="rewardUserName != null and rewardUserName != ''">
AND a.reward_user_name LIKE CONCAT('%', #{rewardUserName}, '%')
</if>
<if test="storeNumOrName != null and storeNumOrName != ''">
AND (b.store_num LIKE CONCAT('%', #{storeNumOrName}, '%') OR b.store_name LIKE CONCAT('%', #{storeNumOrName}, '%'))
</if>
<if test="storeId != null and storeId != ''">
AND a.store_id = #{storeId}
</if>
</where>
GROUP BY a.store_id, a.reward_user_id, DATE_FORMAT(a.pay_date, '%Y-%m')
ORDER BY a.pay_date DESC, a.store_id ASC, a.reward_user_id ASC
</select>
<select id="getMonthlyStatisticsGroupByStore" resultMap="BaseResultMap">
SELECT store_id, reward_user_id, reward_user_name, SUM(reward_amount) AS reward_amount
FROM bonus_new_product_employee
<where>
<if test="payMonth != null and payMonth != ''">
AND DATE_FORMAT(pay_date, '%Y-%m') = #{payMonth}
</if>
</where>
GROUP BY store_id, reward_user_id
</select>
</mapper>

View File

@@ -0,0 +1,58 @@
<?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.cool.store.mapper.bonus.BonusNewProductRecipeEmployeeMapper">
<resultMap id="BaseResultMap" type="com.cool.store.entity.bonus.BonusNewProductRecipeEmployeeDO">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="product_recipe_id" jdbcType="BIGINT" property="productRecipeId" />
<result column="rule_id" jdbcType="BIGINT" property="ruleId" />
<result column="store_id" jdbcType="VARCHAR" property="storeId" />
<result column="pay_date" jdbcType="DATE" property="payDate" />
<result column="recipe_no" jdbcType="VARCHAR" property="recipeNo" />
<result column="recipe_name" jdbcType="VARCHAR" property="recipeName" />
<result column="basic_reward_amount" jdbcType="DECIMAL" property="basicRewardAmount" />
<result column="sales_volume" jdbcType="INTEGER" property="salesVolume" />
<result column="excess_reward_amount" jdbcType="DECIMAL" property="excessRewardAmount" />
<result column="reward_ratio" jdbcType="DECIMAL" property="rewardRatio" />
<result column="reward_user_name" jdbcType="VARCHAR" property="rewardUserName" />
<result column="reward_user_id" jdbcType="VARCHAR" property="rewardUserId" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
</resultMap>
<insert id="insertBatch">
insert into bonus_new_product_recipe_employee (id, product_recipe_id, rule_id, store_id, pay_date, recipe_no, recipe_name, basic_reward_amount, excess_reward_amount, reward_ratio, reward_user_name, reward_user_id, sales_volume)
values
<foreach collection="list" item="item" separator=",">
(#{item.id}, #{item.productRecipeId}, #{item.ruleId}, #{item.storeId}, #{item.payDate}, #{item.recipeNo}, #{item.recipeName}, #{item.basicRewardAmount}, #{item.excessRewardAmount}, #{item.rewardRatio}, #{item.rewardUserName}, #{item.rewardUserId}, #{item.salesVolume})
</foreach>
</insert>
<select id="monthlyStatistics" resultMap="BaseResultMap">
SELECT a.store_id, a.pay_date, a.recipe_no, a.recipe_name, SUM(a.sales_volume) sales_volume, SUM(a.basic_reward_amount) basic_reward_amount, SUM(a.excess_reward_amount) excess_reward_amount, a.reward_user_id, a.reward_user_name
FROM bonus_new_product_recipe_employee a
<if test="storeNumOrName != null and storeNumOrName != ''">
INNER JOIN store_${enterpriseId} b ON a.store_id = b.store_id AND b.is_delete = 'effective'
</if>
<where>
<if test="storeNumOrName != null and storeNumOrName != ''">
AND (b.store_num LIKE CONCAT('%', #{storeNumOrName}, '%') OR b.store_name LIKE CONCAT('%', #{storeNumOrName}, '%'))
</if>
<if test="startDate != null">
AND DATE_FORMAT(a.pay_date, '%Y-%m') >= DATE_FORMAT(#{startDate}, '%Y-%m')
</if>
<if test="endDate != null">
AND DATE_FORMAT(a.pay_date, '%Y-%m') &lt;= DATE_FORMAT(#{endDate}, '%Y-%m')
</if>
<if test="rewardUserName != null and rewardUserName != ''">
AND a.reward_user_name LIKE CONCAT('%', #{rewardUserName}, '%')
</if>
<if test="recipeNoOrName != null and recipeNoOrName != ''">
AND (a.recipe_no LIKE CONCAT('%', #{recipeNoOrName}, '%') OR a.recipe_name LIKE CONCAT('%', #{recipeNoOrName}, '%'))
</if>
</where>
GROUP BY a.store_id, DATE_FORMAT(a.pay_date, '%Y-%m'), a.reward_user_id, a.recipe_no
ORDER BY a.pay_date DESC, a.store_id ASC, a.reward_user_id ASC, a.recipe_no ASC
</select>
</mapper>

View File

@@ -0,0 +1,78 @@
<?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.cool.store.mapper.bonus.BonusNewProductRecipeMapper">
<resultMap id="BaseResultMap" type="com.cool.store.entity.bonus.BonusNewProductRecipeDO">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="rule_id" jdbcType="BIGINT" property="ruleId" />
<result column="store_id" jdbcType="VARCHAR" property="storeId" />
<result column="pay_date" jdbcType="DATE" property="payDate" />
<result column="recipe_no" jdbcType="VARCHAR" property="recipeNo" />
<result column="recipe_name" jdbcType="VARCHAR" property="recipeName" />
<result column="min_standard_num" jdbcType="INTEGER" property="minStandardNum" />
<result column="reward_amount" jdbcType="DECIMAL" property="rewardAmount" />
<result column="excess_standard_num" jdbcType="INTEGER" property="excessStandardNum" />
<result column="excess_amount" jdbcType="DECIMAL" property="excessAmount" />
<result column="sales_volume" jdbcType="INTEGER" property="salesVolume" />
<result column="basic_reward_amount" jdbcType="DECIMAL" property="basicRewardAmount" />
<result column="excess_reward_amount" jdbcType="DECIMAL" property="excessRewardAmount" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
</resultMap>
<sql id="Base_Column_List">
id, rule_id, store_id, pay_date, recipe_no, recipe_name, min_standard_num, reward_amount, excess_standard_num, excess_amount, sales_volume, basic_reward_amount, excess_reward_amount, create_time
</sql>
<insert id="insertBatch" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
INSERT INTO bonus_new_product_recipe (rule_id, store_id, pay_date, recipe_no, recipe_name, min_standard_num, reward_amount, excess_standard_num, excess_amount, sales_volume, basic_reward_amount, excess_reward_amount) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.ruleId}, #{item.storeId}, #{item.payDate}, #{item.recipeNo}, #{item.recipeName}, #{item.minStandardNum}, #{item.rewardAmount}, #{item.excessStandardNum}, #{item.excessAmount}, #{item.salesVolume}, #{item.basicRewardAmount}, #{item.excessRewardAmount})
</foreach>
</insert>
<select id="monthlyStatistics" resultMap="BaseResultMap">
SELECT a.store_id, a.recipe_no, a.recipe_name, a.pay_date, SUM(a.basic_reward_amount) basic_reward_amount, SUM(a.excess_reward_amount) excess_reward_amount
FROM bonus_new_product_recipe a
<if test="storeNumOrName != null and storeNumOrName != ''">
INNER JOIN store_${enterpriseId} b ON a.store_id = b.store_id AND b.is_delete = 'effective'
</if>
<where>
<if test="storeNumOrName != null and storeNumOrName != ''">
AND (b.store_num LIKE CONCAT('%', #{storeNumOrName}, '%') OR b.store_name LIKE CONCAT('%', #{storeNumOrName}, '%'))
</if>
<if test="startDate != null">
AND DATE_FORMAT(a.pay_date, '%Y-%m') >= DATE_FORMAT(#{startDate}, '%Y-%m')
</if>
<if test="endDate != null">
AND DATE_FORMAT(a.pay_date, '%Y-%m') &lt;= DATE_FORMAT(#{endDate}, '%Y-%m')
</if>
<if test="recipeNoOrName != null and recipeNoOrName != ''">
AND (a.recipe_no LIKE CONCAT('%', #{recipeNoOrName}, '%') OR a.recipe_name LIKE CONCAT('%', #{recipeNoOrName}, '%'))
</if>
</where>
GROUP BY a.store_id, a.recipe_no, DATE_FORMAT(a.pay_date, '%Y-%m')
ORDER BY a.pay_date DESC, a.store_id ASC, a.recipe_no ASC
</select>
<select id="selectListByCondition" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List" />
FROM bonus_new_product_recipe
<where>
<if test="storeId != null and storeId != ''">
AND store_id = #{storeId}
</if>
<if test="recipeNo != null and recipeNo != ''">
AND recipe_no = #{recipeNo}
</if>
<if test="startDate != null">
AND DATE_FORMAT(pay_date, '%Y-%m-%d') >= DATE_FORMAT(#{startDate}, '%Y-%m-%d')
</if>
<if test="endDate != null">
AND DATE_FORMAT(pay_date, '%Y-%m-%d') &lt;= DATE_FORMAT(#{endDate}, '%Y-%m-%d')
</if>
</where>
ORDER BY create_time DESC, store_id ASC
</select>
</mapper>

View File

@@ -0,0 +1,47 @@
<?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.cool.store.mapper.bonus.BonusNewProductStoreMapper">
<resultMap id="BaseResultMap" type="com.cool.store.entity.bonus.BonusNewProductStoreDO">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="rule_id" jdbcType="BIGINT" property="ruleId" />
<result column="store_id" jdbcType="VARCHAR" property="storeId" />
<result column="pay_date" jdbcType="DATE" property="payDate" />
<result column="amount_total" jdbcType="DECIMAL" property="amountTotal" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
</resultMap>
<select id="selectCountByRuleIdAndPayDate" resultType="int">
SELECT COUNT(1) FROM bonus_new_product_store
WHERE rule_id = #{ruleId} AND DATE_FORMAT(pay_date, '%Y-%m-%d') = #{payDate}
</select>
<select id="monthlyStatistics" resultMap="BaseResultMap">
SELECT a.rule_id, a.store_id, a.pay_date, SUM(a.amount_total) amount_total
FROM bonus_new_product_store a
<if test="storeNumOrName != null and storeNumOrName != ''">
INNER JOIN store_${enterpriseId} b ON a.store_id = b.store_id AND b.is_delete = 'effective'
</if>
<where>
<if test="storeNumOrName != null and storeNumOrName != ''">
AND (b.store_num LIKE CONCAT('%', #{storeNumOrName}, '%') OR b.store_name LIKE CONCAT('%', #{storeNumOrName}, '%'))
</if>
<if test="startDate != null">
AND DATE_FORMAT(a.pay_date, '%Y-%m') >= DATE_FORMAT(#{startDate}, '%Y-%m')
</if>
<if test="endDate != null">
AND DATE_FORMAT(a.pay_date, '%Y-%m') &lt;= DATE_FORMAT(#{endDate}, '%Y-%m')
</if>
<if test="storeId != null and storeId != ''">
AND a.store_id = #{storeId}
</if>
<if test="ruleId != null">
AND a.rule_id = #{ruleId}
</if>
</where>
GROUP BY a.store_id, a.rule_id, DATE_FORMAT(a.pay_date, '%Y-%m')
ORDER BY a.pay_date DESC, a.store_id ASC, a.rule_id ASC
</select>
</mapper>

View File

@@ -0,0 +1,67 @@
<?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.cool.store.mapper.bonus.BonusReceivedEmployeeMapper">
<resultMap id="BaseResultMap" type="com.cool.store.entity.bonus.BonusReceivedEmployeeDO">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="received_store_id" jdbcType="BIGINT" property="receivedStoreId" />
<result column="rule_id" jdbcType="BIGINT" property="ruleId" />
<result column="store_id" jdbcType="VARCHAR" property="storeId" />
<result column="pay_date" jdbcType="DATE" property="payDate" />
<result column="reward_ratio" jdbcType="DECIMAL" property="rewardRatio" />
<result column="received_amount" jdbcType="DECIMAL" property="receivedAmount" />
<result column="reward_user_name" jdbcType="VARCHAR" property="rewardUserName" />
<result column="reward_user_id" jdbcType="VARCHAR" property="rewardUserId" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
</resultMap>
<insert id="insertBatch" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
INSERT INTO bonus_received_employee(received_store_id, rule_id, store_id, pay_date, reward_ratio, received_amount, reward_user_name, reward_user_id)
VALUES
<foreach collection="list" item="item" separator=",">
(#{item.receivedStoreId}, #{item.ruleId}, #{item.storeId}, #{item.payDate}, #{item.rewardRatio}, #{item.receivedAmount}, #{item.rewardUserName}, #{item.rewardUserId})
</foreach>
</insert>
<select id="selectByReceivedStoreId" resultMap="BaseResultMap">
SELECT id, received_store_id, rule_id, store_id, pay_date, reward_ratio, received_amount, reward_user_name, reward_user_id, create_time
FROM bonus_received_employee
WHERE received_store_id = #{receivedStoreId}
ORDER BY id
</select>
<select id="selectEmployeeListByCondition" resultMap="BaseResultMap">
SELECT e.id, e.received_store_id, e.rule_id, e.store_id, e.pay_date, e.reward_ratio, e.received_amount, e.reward_user_name, e.reward_user_id, e.create_time
FROM bonus_received_employee e
<if test="storeNumOrName != null and storeNumOrName != ''">
INNER JOIN store_${enterpriseId} st ON e.store_id = st.store_id AND st.is_delete = 'effective'
</if>
<where>
<if test="storeNumOrName != null and storeNumOrName != ''">
AND (st.store_num LIKE CONCAT('%', #{storeNumOrName}, '%') OR st.store_name LIKE CONCAT('%', #{storeNumOrName}, '%'))
</if>
<if test="startMonth != null">
AND e.pay_date &gt;= #{startMonth}
</if>
<if test="endMonth != null">
AND e.pay_date &lt;= #{endMonth}
</if>
<if test="rewardUserName != null and rewardUserName != ''">
AND e.reward_user_name LIKE CONCAT('%', #{rewardUserName}, '%')
</if>
<if test="storeId != null and storeId != ''">
AND e.store_id = #{storeId}
</if>
</where>
ORDER BY e.create_time DESC, e.store_id ASC
</select>
<select id="getMonthlyStatisticsGroupByStore" resultMap="BaseResultMap">
SELECT store_id, reward_user_id, reward_user_name, SUM(received_amount) AS received_amount
FROM bonus_received_employee
WHERE DATE_FORMAT(pay_date, '%Y-%m') = #{payMonth}
GROUP BY store_id, reward_user_id
</select>
</mapper>

View File

@@ -0,0 +1,47 @@
<?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.cool.store.mapper.bonus.BonusReceivedStoreMapper">
<resultMap id="BaseResultMap" type="com.cool.store.entity.bonus.BonusReceivedStoreDO">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="rule_id" jdbcType="BIGINT" property="ruleId" />
<result column="store_id" jdbcType="VARCHAR" property="storeId" />
<result column="pay_date" jdbcType="DATE" property="payDate" />
<result column="received_monthly" jdbcType="DECIMAL" property="receivedMonthly" />
<result column="business_days" jdbcType="INTEGER" property="businessDays" />
<result column="received_daily" jdbcType="DECIMAL" property="receivedDaily" />
<result column="received_daily_last" jdbcType="DECIMAL" property="receivedDailyLast" />
<result column="amount_total" jdbcType="DECIMAL" property="amountTotal" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
</resultMap>
<select id="selectCountByRuleIdAndPayDate" resultType="int">
SELECT COUNT(1) FROM bonus_received_store
WHERE rule_id = #{ruleId} AND DATE_FORMAT(pay_date, '%Y-%m') = #{payDate}
</select>
<select id="selectListByCondition" resultMap="BaseResultMap">
SELECT a.id, a.rule_id, a.store_id, a.pay_date, a.received_monthly, a.business_days, a.received_daily, a.received_daily_last, a.amount_total, a.create_time
FROM bonus_received_store a
<if test="storeNumOrName != null and storeNumOrName != ''">
INNER JOIN store_${enterpriseId} b ON a.store_id = b.store_id AND b.is_delete = 'effective'
</if>
<where>
<if test="storeNumOrName != null and storeNumOrName != ''">
AND (b.store_num LIKE CONCAT('%', #{storeNumOrName}, '%') OR b.store_name LIKE CONCAT('%', #{storeNumOrName}, '%'))
</if>
<if test="startMonth != null">
AND a.pay_date &gt;= #{startMonth}
</if>
<if test="endMonth != null">
AND a.pay_date &lt;= #{endMonth}
</if>
<if test="storeId != null and storeId != ''">
AND a.store_id = #{storeId}
</if>
</where>
ORDER BY a.create_time DESC
</select>
</mapper>

View File

@@ -0,0 +1,90 @@
package com.cool.store.entity.bonus;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
import javax.persistence.*;
/**
* 奖金发放规则
*/
@Data
@Table(name = "bonus_distribution_rule")
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BonusDistributionRuleDO {
/**
* id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 规则类型1-实收 2-新品销售
*/
private Integer type;
/**
* 门店id
*/
@Column(name = "store_id")
private String storeId;
/**
* 生效开始年月
*/
@Column(name = "start_date")
private Date startDate;
/**
* 生效结束年月
*/
@Column(name = "end_date")
private Date endDate;
/**
* 创建时间
*/
@Column(name = "create_time")
private Date createTime;
/**
* 创建人id
*/
@Column(name = "create_user_id")
private String createUserId;
/**
* 更新时间
*/
@Column(name = "update_time")
private Date updateTime;
/**
* 更新人id
*/
@Column(name = "update_user_id")
private String updateUserId;
/**
* 奖金规则配置
*/
@Column(name = "bonus_config")
private String bonusConfig;
/**
* 分配规则配置
*/
@Column(name = "distribute_config")
private String distributeConfig;
/**
* 是否启用0否1是
*/
private Integer enable;
}

View File

@@ -0,0 +1,63 @@
package com.cool.store.entity.bonus;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.*;
/**
* 员工奖励明细
*/
@Data
@Table(name = "bonus_employee_reward_detail")
public class BonusEmployeeRewardDetailDO {
/**
* id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 门店id
*/
@Column(name = "store_id")
private String storeId;
/**
* 发放年月
*/
@Column(name = "pay_date")
private Date payDate;
/**
* 奖励人姓名
*/
@Column(name = "reward_user_name")
private String rewardUserName;
/**
* 奖励人id
*/
@Column(name = "reward_user_id")
private String rewardUserId;
/**
* 实收奖励金额
*/
@Column(name = "received_amount")
private BigDecimal receivedAmount;
/**
* 新品销售奖励金额
*/
@Column(name = "new_project_amount")
private BigDecimal newProjectAmount;
/**
* 创建时间
*/
@Column(name = "create_time")
private Date createTime;
}

View File

@@ -0,0 +1,75 @@
package com.cool.store.entity.bonus;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.*;
/**
* 新品销售奖金-员工
*/
@Data
@Table(name = "bonus_new_product_employee")
public class BonusNewProductEmployeeDO {
/**
* id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* bonus_new_product_store.id
*/
@Column(name = "product_store_id")
private Long productStoreId;
/**
* 规则id
*/
@Column(name = "rule_id")
private Long ruleId;
/**
* 门店id
*/
@Column(name = "store_id")
private String storeId;
/**
* 发放年月日
*/
@Column(name = "pay_date")
private Date payDate;
/**
* 奖励比例(%
*/
@Column(name = "reward_ratio")
private BigDecimal rewardRatio;
/**
* 奖励金额
*/
@Column(name = "reward_amount")
private BigDecimal rewardAmount;
/**
* 奖励人姓名
*/
@Column(name = "reward_user_name")
private String rewardUserName;
/**
* 奖励人id
*/
@Column(name = "reward_user_id")
private String rewardUserId;
/**
* 创建时间
*/
@Column(name = "create_time")
private Date createTime;
}

View File

@@ -0,0 +1,99 @@
package com.cool.store.entity.bonus;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.*;
/**
* 新品销售奖金-菜品
*/
@Data
@Table(name = "bonus_new_product_recipe")
public class BonusNewProductRecipeDO {
/**
* id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 规则id
*/
@Column(name = "rule_id")
private Long ruleId;
/**
* 门店id
*/
@Column(name = "store_id")
private String storeId;
/**
* 发放年月日
*/
@Column(name = "pay_date")
private Date payDate;
/**
* 菜品编码
*/
@Column(name = "recipe_no")
private String recipeNo;
/**
* 菜品名称
*/
@Column(name = "recipe_name")
private String recipeName;
/**
* 日销量奖励最低达标数量
*/
@Column(name = "min_standard_num")
private Integer minStandardNum;
/**
* 销售奖励(元/个)
*/
@Column(name = "reward_amount")
private BigDecimal rewardAmount;
/**
* 日销量超额奖励基数
*/
@Column(name = "excess_standard_num")
private Integer excessStandardNum;
/**
* 超额后额外销售奖励(元/个)
*/
@Column(name = "excess_amount")
private BigDecimal excessAmount;
/**
* 销量
*/
@Column(name = "sales_volume")
private Integer salesVolume;
/**
* 基础奖金
*/
@Column(name = "basic_reward_amount")
private BigDecimal basicRewardAmount;
/**
* 超额奖金
*/
@Column(name = "excess_reward_amount")
private BigDecimal excessRewardAmount;
/**
* 创建时间
*/
@Column(name = "create_time")
private Date createTime;
}

View File

@@ -0,0 +1,99 @@
package com.cool.store.entity.bonus;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.*;
/**
* 新品销售奖金-菜品-员工
*/
@Data
@Table(name = "bonus_new_product_recipe_employee")
public class BonusNewProductRecipeEmployeeDO {
/**
* id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* bonus_new_product_recipe.id
*/
@Column(name = "product_recipe_id")
private Long productRecipeId;
/**
* 规则id
*/
@Column(name = "rule_id")
private Long ruleId;
/**
* 门店id
*/
@Column(name = "store_id")
private String storeId;
/**
* 发放年月日
*/
@Column(name = "pay_date")
private Date payDate;
/**
* 菜品编码
*/
@Column(name = "recipe_no")
private String recipeNo;
/**
* 菜品名称
*/
@Column(name = "recipe_name")
private String recipeName;
/**
* 销量
*/
@Column(name = "sales_volume")
private Integer salesVolume;
/**
* 基础奖金
*/
@Column(name = "basic_reward_amount")
private BigDecimal basicRewardAmount;
/**
* 超额奖金
*/
@Column(name = "excess_reward_amount")
private BigDecimal excessRewardAmount;
/**
* 奖励比例(%
*/
@Column(name = "reward_ratio")
private BigDecimal rewardRatio;
/**
* 奖励人姓名
*/
@Column(name = "reward_user_name")
private String rewardUserName;
/**
* 奖励人id
*/
@Column(name = "reward_user_id")
private String rewardUserId;
/**
* 创建时间
*/
@Column(name = "create_time")
private Date createTime;
}

View File

@@ -0,0 +1,51 @@
package com.cool.store.entity.bonus;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.*;
/**
* 新品销售奖金-门店
*/
@Data
@Table(name = "bonus_new_product_store")
public class BonusNewProductStoreDO {
/**
* id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 规则id
*/
@Column(name = "rule_id")
private Long ruleId;
/**
* 门店id
*/
@Column(name = "store_id")
private String storeId;
/**
* 发放月份
*/
@Column(name = "pay_date")
private Date payDate;
/**
* 奖金总计
*/
@Column(name = "amount_total")
private BigDecimal amountTotal;
/**
* 创建时间
*/
@Column(name = "create_time")
private Date createTime;
}

View File

@@ -0,0 +1,75 @@
package com.cool.store.entity.bonus;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.*;
/**
* 实收奖金发放-员工
*/
@Data
@Table(name = "bonus_received_employee")
public class BonusReceivedEmployeeDO {
/**
* id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* bonus_received_store.id
*/
@Column(name = "received_store_id")
private Long receivedStoreId;
/**
* 规则id
*/
@Column(name = "rule_id")
private Long ruleId;
/**
* 门店id
*/
@Column(name = "store_id")
private String storeId;
/**
* 发放月份
*/
@Column(name = "pay_date")
private Date payDate;
/**
* 奖励比例(%
*/
@Column(name = "reward_ratio")
private BigDecimal rewardRatio;
/**
* 实收奖励金额
*/
@Column(name = "received_amount")
private BigDecimal receivedAmount;
/**
* 奖励人姓名
*/
@Column(name = "reward_user_name")
private String rewardUserName;
/**
* 奖励人id
*/
@Column(name = "reward_user_id")
private String rewardUserId;
/**
* 创建时间
*/
@Column(name = "create_time")
private Date createTime;
}

View File

@@ -0,0 +1,75 @@
package com.cool.store.entity.bonus;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.*;
/**
* 实收奖金发放-门店
*/
@Data
@Table(name = "bonus_received_store")
public class BonusReceivedStoreDO {
/**
* id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 规则id
*/
@Column(name = "rule_id")
private Long ruleId;
/**
* 门店id
*/
@Column(name = "store_id")
private String storeId;
/**
* 发放月份
*/
@Column(name = "pay_date")
private Date payDate;
/**
* 月度实收
*/
@Column(name = "received_monthly")
private BigDecimal receivedMonthly;
/**
* 月度营业天数
*/
@Column(name = "business_days")
private Integer businessDays;
/**
* 日均实收
*/
@Column(name = "received_daily")
private BigDecimal receivedDaily;
/**
* 上月日均实收
*/
@Column(name = "received_daily_last")
private BigDecimal receivedDailyLast;
/**
* 奖金总计
*/
@Column(name = "amount_total")
private BigDecimal amountTotal;
/**
* 创建时间
*/
@Column(name = "create_time")
private Date createTime;
}

View File

@@ -0,0 +1,33 @@
package com.cool.store.request.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
* <p>
* 新品销售试算
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class BonusProductComputeRequest {
@ApiModelProperty("菜品销量")
@NotEmpty(message = "菜品销量不能为空")
private List<BonusProductRecipeCompute> recipeSales;
@ApiModelProperty("新品销售奖金规则配置(新品销售必填)")
@NotEmpty(message = "新品销售奖金规则配置不能为空")
@Valid
private List<BonusRuleProductConfig> productConfigs;
@ApiModelProperty("分配规则")
@NotEmpty(message = "分配规则不能为空")
@Valid
private List<BonusRuleDistributeConfig> distributeConfigs;
}

View File

@@ -0,0 +1,36 @@
package com.cool.store.request.bonus;
import com.cool.store.common.PageBasicInfo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* <p>
* 员工新品查询Request
* </p>
*
* @author wangff
* @since 2026/4/23
*/
@Data
public class BonusProductEmployeeQueryRequest extends PageBasicInfo {
@ApiModelProperty("门店编码/名称")
private String storeNumOrName;
@ApiModelProperty("开始日期")
private Date startDate;
@ApiModelProperty("结束日期")
private Date endDate;
@ApiModelProperty("奖励人姓名")
private String rewardUserName;
@ApiModelProperty("菜品编码或名称")
private String recipeNoOrName;
@ApiModelProperty("门店id")
private String storeId;
}

View File

@@ -0,0 +1,33 @@
package com.cool.store.request.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* <p>
* 新品销售月度查询Request
* </p>
*
* @author wangff
* @since 2026/4/22
*/
@Data
public class BonusProductMonthlyQueryRequest {
@ApiModelProperty("规则id")
private Long ruleId;
@ApiModelProperty("门店id")
@NotBlank(message = "门店id不能为空")
private String storeId;
@ApiModelProperty("发放月份")
@NotNull(message = "发放月份不能为空")
private Date payDate;
@ApiModelProperty("奖励人id")
private String rewardUserId;
}

View File

@@ -0,0 +1,29 @@
package com.cool.store.request.bonus;
import com.cool.store.common.PageBasicInfo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* 门店新品销售奖金发放列表查询请求
*
* @author wangff
* @since 2026/4/22
*/
@Data
public class BonusProductQueryRequest extends PageBasicInfo {
@ApiModelProperty("门店编码/名称")
private String storeNumOrName;
@ApiModelProperty("开始日期")
private Date startDate;
@ApiModelProperty("结束日期")
private Date endDate;
@ApiModelProperty("菜品编码或名称")
private String recipeNoOrName;
}

View File

@@ -0,0 +1,29 @@
package com.cool.store.request.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
/**
* <p>
* 新品销售试算菜品
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BonusProductRecipeCompute {
@ApiModelProperty("菜品编码")
@NotNull(message = "菜品编码不能为空")
private String recipeNo;
@ApiModelProperty("销量")
@NotNull(message = "销量不能为空")
private Integer salesVolume;
}

View File

@@ -0,0 +1,37 @@
package com.cool.store.request.bonus;
import com.cool.store.common.PageBasicInfo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* <p>
* 门店菜品员工查询Request
* </p>
*
* @author wangff
* @since 2026/4/23
*/
@Data
public class BonusProductRecipeEmployeeQueryRequest extends PageBasicInfo {
@ApiModelProperty("门店id")
@NotBlank(message = "门店id不能为空")
private String storeId;
@ApiModelProperty("菜品编码")
private String recipeNo;
@ApiModelProperty("奖励人id")
@NotNull(message = "奖励人id不能为空")
private String rewardUserId;
@ApiModelProperty("开始日期")
private Date startDate;
@ApiModelProperty("结束日期")
private Date endDate;
}

View File

@@ -0,0 +1,34 @@
package com.cool.store.request.bonus;
import com.cool.store.common.PageBasicInfo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* <p>
* 门店菜品查询Request
* </p>
*
* @author wangff
* @since 2026/4/22
*/
@Data
public class BonusProductRecipeQueryRequest extends PageBasicInfo {
@ApiModelProperty("门店id")
@NotBlank(message = "门店id不能为空")
private String storeId;
@ApiModelProperty("菜品编码")
@NotNull(message = "菜品编码不能为空")
private String recipeNo;
@ApiModelProperty("开始日期")
private Date startDate;
@ApiModelProperty("结束日期")
private Date endDate;
}

View File

@@ -0,0 +1,43 @@
package com.cool.store.request.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.List;
/**
* <p>
* 月度实收试算
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class BonusReceivedComputeRequest {
@ApiModelProperty("月度实收")
@NotNull(message = "月度实收不能为空")
private BigDecimal receivedMonthly;
@ApiModelProperty("月度营业天数")
@NotNull(message = "月度营业天数不能为空")
private Integer businessDays;
@ApiModelProperty("日均实收小于等于该值不发放奖金(实收必填)")
@NotNull(message = "日均实收小于等于该值不发放奖金(实收必填)不能为空")
private BigDecimal receivedStart;
@ApiModelProperty("实收奖励规则配置(实收必填)")
@NotNull(message = "实收奖励规则配置(实收必填)不能为空")
@Valid
private List<BonusRuleReceivedConfig> receivedConfigs;
@ApiModelProperty("分配规则")
@NotNull(message = "分配规则不能为空")
@Valid
private List<BonusRuleDistributeConfig> distributeConfigs;
}

View File

@@ -0,0 +1,32 @@
package com.cool.store.request.bonus;
import com.cool.store.common.PageBasicInfo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* 员工实收奖金发放列表查询请求
*
* @author wangff
* @since 2026/4/22
*/
@Data
public class BonusReceivedEmployeeQueryRequest extends PageBasicInfo {
@ApiModelProperty("门店编码/名称")
private String storeNumOrName;
@ApiModelProperty("开始年月")
private Date startMonth;
@ApiModelProperty("结束年月")
private Date endMonth;
@ApiModelProperty("奖励人姓名")
private String rewardUserName;
@ApiModelProperty("门店id")
private String storeId;
}

View File

@@ -0,0 +1,29 @@
package com.cool.store.request.bonus;
import com.cool.store.common.PageBasicInfo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* 门店实收奖金发放列表查询请求
*
* @author wangff
* @since 2026/4/22
*/
@Data
public class BonusReceivedStoreQueryRequest extends PageBasicInfo {
@ApiModelProperty("门店编码/名称")
private String storeNumOrName;
@ApiModelProperty("开始年月")
private Date startMonth;
@ApiModelProperty("结束年月")
private Date endMonth;
@ApiModelProperty("门店id")
private String storeId;
}

View File

@@ -0,0 +1,35 @@
package com.cool.store.request.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* <p>
* 奖金发放规则新增Request
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class BonusRuleAddRequest {
@ApiModelProperty("门店id")
@NotBlank(message = "门店id不能为空")
private String storeId;
@ApiModelProperty("规则类型1-实收 2-新品销售")
@NotNull(message = "规则类型不能为空")
private Integer type;
@ApiModelProperty("生效开始年月")
@NotNull(message = "生效开始年月不能为空")
private Date startDate;
@ApiModelProperty("生效结束年月")
@NotNull(message = "生效结束年月不能为空")
private Date endDate;
}

View File

@@ -0,0 +1,26 @@
package com.cool.store.request.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* <p>
* 分配规则
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class BonusRuleDistributeConfig {
@ApiModelProperty("奖励人id")
private String rewardUserId;
@ApiModelProperty("奖励人姓名")
private String rewardUserName;
@ApiModelProperty("奖励比例(%")
private BigDecimal rewardRatio;
}

View File

@@ -0,0 +1,25 @@
package com.cool.store.request.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* <p>
* 奖金发放规则启用Request
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class BonusRuleEnableRequest {
@ApiModelProperty("规则id")
@NotNull(message = "规则id不能为空")
private Long id;
@ApiModelProperty("是否启用0否1是")
@NotNull(message = "是否启用不能为空")
private Integer enable;
}

View File

@@ -0,0 +1,35 @@
package com.cool.store.request.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* <p>
* 新品销售规则配置
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class BonusRuleProductConfig {
@ApiModelProperty("菜品编码")
private String recipeNo;
@ApiModelProperty("菜品名称")
private String recipeName;
@ApiModelProperty("日销量奖励最低达标数量")
private Integer minStandardNum;
@ApiModelProperty("销售奖励(元/个)")
private BigDecimal rewardAmount;
@ApiModelProperty("日销量超额奖励基数")
private Integer excessStandardNum;
@ApiModelProperty("超额后额外销售奖励(元/个)")
private BigDecimal excessAmount;
}

View File

@@ -0,0 +1,29 @@
package com.cool.store.request.bonus;
import com.cool.store.common.PageBasicInfo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* <p>
* 规则查询Request
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class BonusRuleQueryRequest extends PageBasicInfo {
@ApiModelProperty("门店编码或名称")
private String storeNumOrName;
@ApiModelProperty("规则类型1-实收 2-新品销售")
private Integer type;
@ApiModelProperty("是否启用0否1是")
private Integer enable;
@ApiModelProperty("门店id")
private String storeId;
}

View File

@@ -0,0 +1,30 @@
package com.cool.store.request.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
/**
* <p>
* 实收规则
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class BonusRuleReceivedConfig {
@ApiModelProperty("实收小于等于")
@NotNull(message = "实收小于等于不能为空")
private BigDecimal le;
@ApiModelProperty("实收大于")
@NotNull(message = "实收大于不能为空")
private BigDecimal gt;
@ApiModelProperty("奖励比例(%")
@NotNull(message = "奖励比例不能为空")
private BigDecimal rewardRatio;
}

View File

@@ -0,0 +1,47 @@
package com.cool.store.request.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* <p>
* 奖金发放规则编辑Request
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class BonusRuleUpdateRequest {
@ApiModelProperty("id")
@NotNull(message = "id不能为空")
private Long id;
@ApiModelProperty("生效开始年月")
@NotNull(message = "生效开始年月不能为空")
private Date startDate;
@ApiModelProperty("生效结束年月")
@NotNull(message = "生效结束年月不能为空")
private Date endDate;
@ApiModelProperty("日均实收小于等于该值不发放奖金(实收必填)")
private BigDecimal receivedStart;
@ApiModelProperty("实收奖励规则配置(实收必填)")
private List<BonusRuleReceivedConfig> receivedConfigs;
@ApiModelProperty("新品销售奖金规则配置(新品销售必填)")
private List<BonusRuleProductConfig> productConfigs;
@ApiModelProperty("分配规则")
@NotEmpty(message = "分配规则不能为空")
private List<BonusRuleDistributeConfig> distributeConfigs;
}

View File

@@ -0,0 +1,27 @@
package com.cool.store.request.storeopen;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 门店月营收请求
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class StoreMonthRevenueRequest {
@ApiModelProperty("门店编码")
@NotBlank(message = "门店编码不能为空")
private String storeNum;
@ApiModelProperty("开始月份格式yyyy-MM")
@NotBlank(message = "开始月份不能为空")
private String startDate;
@ApiModelProperty("结束月份格式yyyy-MM")
@NotBlank(message = "结束月份不能为空")
private String endDate;
}

View File

@@ -0,0 +1,27 @@
package com.cool.store.request.storeopen;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 门店菜品日销量请求
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class StoreRecipeDailySalesRequest {
@ApiModelProperty("门店编码")
@NotBlank(message = "门店编码不能为空")
private String storeNum;
@ApiModelProperty("开始日期格式yyyy-MM-dd")
@NotBlank(message = "开始日期不能为空")
private String startDate;
@ApiModelProperty("结束日期格式yyyy-MM-dd")
@NotBlank(message = "结束日期不能为空")
private String endDate;
}

View File

@@ -0,0 +1,19 @@
package com.cool.store.request.storeopen;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 门店菜品种类请求
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class StoreRecipesRequest {
@ApiModelProperty("门店编码")
@NotBlank(message = "门店编码不能为空")
private String storeNum;
}

View File

@@ -0,0 +1,41 @@
package com.cool.store.response.storeopen;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import java.math.BigDecimal;
/**
* 门店月营收响应
*
* @author wangff
* @since 2026/4/20
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class StoreMonthRevenueResponse {
/**
* 月份格式yyyy-MM
*/
private String date;
/**
* 月度实收
*/
private BigDecimal receivedAmount;
/**
* 月度营业天数
*/
private Integer businessDays;
/**
* 当月日均实收
*/
private BigDecimal receivedAmountDaily;
/**
* 上月日均实收
*/
private BigDecimal receivedAmountDailyLastMonth;
}

View File

@@ -0,0 +1,18 @@
package com.cool.store.response.storeopen;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
/**
* 门店开放数据API通用响应
*
* @author wangff
* @since 2026/4/20
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class StoreOpenApiResponse<T> {
private Integer code;
private String msg;
private T data;
}

View File

@@ -0,0 +1,34 @@
package com.cool.store.response.storeopen;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
/**
* 门店菜品日销量响应
*
* @author wangff
* @since 2026/4/20
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class StoreRecipeDailySalesResponse {
/**
* 日期格式yyyy-MM-dd
*/
private String date;
/**
* 日销售量
*/
private Integer sales;
/**
* 菜品编码
*/
private String recipeNo;
/**
* 菜品名称
*/
private String recipeName;
}

View File

@@ -0,0 +1,24 @@
package com.cool.store.response.storeopen;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
/**
* 门店菜品种类响应
*
* @author wangff
* @since 2026/4/20
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class StoreRecipesResponse {
/**
* 菜品编码
*/
private String recipeNo;
/**
* 菜品名称
*/
private String recipeName;
}

View File

@@ -0,0 +1,24 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* <p>
* 基础信息VO
* </p>
*
* @author wangff
* @since 2026/4/23
*/
@Data
public class BonusBasicVO {
@ApiModelProperty("门店id")
private String storeId;
@ApiModelProperty("门店编码")
private String storeNum;
@ApiModelProperty("门店名称")
private String storeName;
}

View File

@@ -0,0 +1,45 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* <p>
* 实算用户金额VO
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BonusComputeUserVO {
@ApiModelProperty("奖励金额")
private BigDecimal rewardAmount;
@ApiModelProperty("奖励人id")
private String rewardUserId;
@ApiModelProperty("奖励人姓名")
private String rewardUserName;
@ApiModelProperty("基础奖金")
private BigDecimal basicRewardAmount;
@ApiModelProperty("超额奖金")
private BigDecimal excessRewardAmount;
@ApiModelProperty("奖励比例(%")
private BigDecimal rewardRatio;
public BonusComputeUserVO(BigDecimal rewardAmount, String rewardUserId, String rewardUserName) {
this.rewardAmount = rewardAmount;
this.rewardUserName = rewardUserName;
this.rewardUserId = rewardUserId;
}
}

View File

@@ -0,0 +1,33 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 员工奖金明细
* </p>
*
* @author wangff
* @since 2026/4/23
*/
@Data
public class BonusEmployeeDetailVO extends BonusBasicVO {
@ApiModelProperty("发放年月")
private Date payDate;
@ApiModelProperty("奖励人姓名")
private String rewardUserName;
@ApiModelProperty("奖励人id")
private String rewardUserId;
@ApiModelProperty("实收奖励金额")
private BigDecimal receivedAmount;
@ApiModelProperty("新品销售奖励金额")
private BigDecimal newProjectAmount;
}

View File

@@ -0,0 +1,27 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* <p>
* 新品销售实算VO
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BonusProductComputeVO {
@ApiModelProperty("菜品信息")
private List<BonusProductRecipeComputeVO> recipes;
@ApiModelProperty("明细(员工级)")
private List<BonusComputeUserVO> detail;
}

View File

@@ -0,0 +1,30 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 门店新品销售奖金方法列表-员工
* </p>
*
* @author wangff
* @since 2026/4/23
*/
@Data
public class BonusProductEmployeeListVO extends BonusBasicVO {
@ApiModelProperty("发放年月")
private Date payDate;
@ApiModelProperty("奖励金额")
private BigDecimal receivedAmount;
@ApiModelProperty("奖励人id")
private String rewardUserId;
@ApiModelProperty("奖励人姓名")
private String rewardUserName;
}

View File

@@ -0,0 +1,48 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
* <p>
* 新品销售菜品实算VO
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class BonusProductRecipeComputeVO {
@ApiModelProperty("菜品编码")
private String recipeNo;
@ApiModelProperty("菜品名称")
private String recipeName;
@ApiModelProperty("日销量奖励最低达标数量")
private Integer minStandardNum;
@ApiModelProperty("销售奖励(元/个)")
private BigDecimal rewardAmount;
@ApiModelProperty("日销量超额奖励基数")
private Integer excessStandardNum;
@ApiModelProperty("超额后额外销售奖励(元/个)")
private BigDecimal excessAmount;
@ApiModelProperty("销量")
private Integer salesVolume;
@ApiModelProperty("基础奖金")
private BigDecimal basicRewardAmount;
@ApiModelProperty("超额奖金")
private BigDecimal excessRewardAmount;
@ApiModelProperty("明细(员工-菜品级)")
private List<BonusComputeUserVO> detail;
}

View File

@@ -0,0 +1,49 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 门店新品销售奖金发放详情-菜品
* </p>
*
* @author wangff
* @since 2026/4/22
*/
@Data
public class BonusProductRecipeDetailVO extends BonusBasicVO {
@ApiModelProperty("菜品编码")
private String recipeNo;
@ApiModelProperty("菜品名称")
private String recipeName;
@ApiModelProperty("发放日期")
private Date payDate;
@ApiModelProperty("日销量奖励最低达标数量")
private Integer minStandardNum;
@ApiModelProperty("销售奖励(元/个)")
private BigDecimal rewardAmount;
@ApiModelProperty("日销量超额奖励基数")
private Integer excessStandardNum;
@ApiModelProperty("超额后额外销售奖励(元/个)")
private BigDecimal excessAmount;
@ApiModelProperty("销量")
private Integer salesVolume;
@ApiModelProperty("基础奖金")
private BigDecimal basicRewardAmount;
@ApiModelProperty("超额奖金")
private BigDecimal excessRewardAmount;
}

View File

@@ -0,0 +1,64 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 门店新品销售菜品员工详情VO
* </p>
*
* @author wangff
* @since 2026/4/23
*/
@Data
public class BonusProductRecipeEmployeeDetailVO extends BonusBasicVO {
@ApiModelProperty("菜品编码")
private String recipeNo;
@ApiModelProperty("菜品名称")
private String recipeName;
@ApiModelProperty("发放月份")
private Date payDate;
@ApiModelProperty("日销量奖励最低达标数量")
private Integer minStandardNum;
@ApiModelProperty("销售奖励(元/个)")
private BigDecimal rewardAmount;
@ApiModelProperty("日销量超额奖励基数")
private Integer excessStandardNum;
@ApiModelProperty("超额后额外销售奖励(元/个)")
private BigDecimal excessAmount;
@ApiModelProperty("销量")
private Integer salesVolume;
@ApiModelProperty("基础奖金")
private BigDecimal basicRewardAmount;
@ApiModelProperty("超额奖金")
private BigDecimal excessRewardAmount;
@ApiModelProperty("奖励人id")
private String rewardUserId;
@ApiModelProperty("奖励比例")
private BigDecimal rewardRatio;
@ApiModelProperty("奖励人姓名")
private String rewardUserName;
@ApiModelProperty("奖金总计")
private BigDecimal amountTotal;
public BigDecimal getAmountTotal() {
return basicRewardAmount.add(excessRewardAmount);
}
}

View File

@@ -0,0 +1,49 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 门店新品销售菜品员工列表VO
* </p>
*
* @author wangff
* @since 2026/4/23
*/
@Data
public class BonusProductRecipeEmployeeListVO extends BonusBasicVO {
@ApiModelProperty("菜品编码")
private String recipeNo;
@ApiModelProperty("菜品名称")
private String recipeName;
@ApiModelProperty("发放月份")
private Date payDate;
@ApiModelProperty("销量")
private Integer salesVolume;
@ApiModelProperty("基础奖金")
private BigDecimal basicRewardAmount;
@ApiModelProperty("超额奖金")
private BigDecimal excessRewardAmount;
@ApiModelProperty("奖励人id")
private String rewardUserId;
@ApiModelProperty("奖励人姓名")
private String rewardUserName;
@ApiModelProperty("奖金总计")
private BigDecimal amountTotal;
public BigDecimal getAmountTotal() {
return basicRewardAmount.add(excessRewardAmount);
}
}

View File

@@ -0,0 +1,41 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 门店新品销售奖金发放列表-菜品
* </p>
*
* @author wangff
* @since 2026/4/22
*/
@Data
public class BonusProductRecipeListVO extends BonusBasicVO {
@ApiModelProperty("菜品编码")
private String recipeNo;
@ApiModelProperty("菜品名称")
private String recipeName;
@ApiModelProperty("发放月份")
private Date payDate;
@ApiModelProperty("基础奖金")
private BigDecimal basicRewardAmount;
@ApiModelProperty("超额奖金")
private BigDecimal excessRewardAmount;
@ApiModelProperty("奖金总计")
private BigDecimal amountTotal;
public BigDecimal getAmountTotal() {
return basicRewardAmount.add(excessRewardAmount);
}
}

View File

@@ -0,0 +1,32 @@
package com.cool.store.vo.bonus;
import com.cool.store.request.bonus.BonusRuleProductConfig;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* 门店新品销售奖金详情VO
*
* @author wangff
* @since 2026/4/22
*/
@Data
public class BonusProductStoreDetailVO {
@ApiModelProperty("门店编码")
private String storeNum;
@ApiModelProperty("门店名称")
private String storeName;
@ApiModelProperty("发放年月")
private Date payDate;
@ApiModelProperty("新品销售奖金规则配置(新品销售必填)")
private List<BonusRuleProductConfig> productConfigs;
@ApiModelProperty("发放明细列表")
private List<EmployeeBonusVO> employeeList;
}

View File

@@ -0,0 +1,25 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* 门店新品销售奖金发放列表VO
*
* @author wangff
* @since 2026/4/22
*/
@Data
public class BonusProductStoreListVO extends BonusBasicVO {
@ApiModelProperty("规则id")
private Long ruleId;
@ApiModelProperty("发放年月")
private Date payDate;
@ApiModelProperty("奖金额总计")
private BigDecimal amountTotal;
}

View File

@@ -0,0 +1,31 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.List;
/**
* <p>
* 实收实算VO
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BonusReceivedComputeVO {
@ApiModelProperty("日均实收")
private BigDecimal receivedDaily;
@ApiModelProperty("奖金总计")
private BigDecimal amountTotal;
@ApiModelProperty("发放明细")
private List<BonusComputeUserVO> detail;
}

View File

@@ -0,0 +1,49 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* 员工实收奖金发放列表VO
*
* @author wangff
* @since 2026/4/22
*/
@Data
public class BonusReceivedEmployeeListVO extends BonusBasicVO {
@ApiModelProperty("id")
private Long id;
@ApiModelProperty("门店实收id")
private Long receivedStoreId;
@ApiModelProperty("发放月份")
private Date payDate;
@ApiModelProperty("月度实收")
private BigDecimal receivedMonthly;
@ApiModelProperty("月度营业天数")
private Integer businessDays;
@ApiModelProperty("日均实收")
private BigDecimal receivedDaily;
@ApiModelProperty("上月日均实收")
private BigDecimal receivedDailyLast;
@ApiModelProperty("实收奖金额总计")
private BigDecimal amountTotal;
@ApiModelProperty("奖励比例")
private BigDecimal rewardRatio;
@ApiModelProperty("实收奖励金额")
private BigDecimal receivedAmount;
@ApiModelProperty("奖励人姓名")
private String rewardUserName;
}

View File

@@ -0,0 +1,57 @@
package com.cool.store.vo.bonus;
import com.cool.store.request.bonus.BonusRuleReceivedConfig;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* 门店实收奖金详情VO
*
* @author wangff
* @since 2026/4/22
*/
@Data
public class BonusReceivedStoreDetailVO {
@ApiModelProperty("id")
private Long id;
@ApiModelProperty("门店id")
private String storeId;
@ApiModelProperty("门店编码")
private String storeNum;
@ApiModelProperty("门店名称")
private String storeName;
@ApiModelProperty("发放月份")
private Date payDate;
@ApiModelProperty("月度实收")
private BigDecimal receivedMonthly;
@ApiModelProperty("月度营业天数")
private Integer businessDays;
@ApiModelProperty("日均实收小于等于该值不发放奖金(实收必填)")
private BigDecimal receivedStart;
@ApiModelProperty("实收奖励规则配置(实收必填)")
private List<BonusRuleReceivedConfig> receivedConfigs;
@ApiModelProperty("日均实收")
private BigDecimal receivedDaily;
@ApiModelProperty("上月日均实收")
private BigDecimal receivedDailyLast;
@ApiModelProperty("奖金额总计")
private BigDecimal amountTotal;
@ApiModelProperty("员工本月奖金发放列表")
private List<EmployeeBonusVO> employeeList;
}

View File

@@ -0,0 +1,38 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* 门店实收奖金发放列表VO
*
* @author wangff
* @since 2026/4/22
*/
@Data
public class BonusReceivedStoreListVO extends BonusBasicVO {
@ApiModelProperty("id")
private Long id;
@ApiModelProperty("发放月份")
private Date payDate;
@ApiModelProperty("月度实收")
private BigDecimal receivedMonthly;
@ApiModelProperty("月度营业天数")
private Integer businessDays;
@ApiModelProperty("日均实收")
private BigDecimal receivedDaily;
@ApiModelProperty("上月日均实收")
private BigDecimal receivedDailyLast;
@ApiModelProperty("奖金额总计")
private BigDecimal amountTotal;
}

View File

@@ -0,0 +1,35 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* <p>
* 奖金发放规则列表VO
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class BonusRuleListVO extends BonusBasicVO {
@ApiModelProperty("id")
private Long id;
@ApiModelProperty("规则类型1-实收 2-新品销售")
private Integer type;
@ApiModelProperty("是否启用0否1是")
private Integer enable;
@ApiModelProperty("生效开始年月")
private Date startDate;
@ApiModelProperty("生效结束年月")
private Date endDate;
@ApiModelProperty("创建时间")
private Date createTime;
}

View File

@@ -0,0 +1,61 @@
package com.cool.store.vo.bonus;
import com.cool.store.request.bonus.BonusRuleDistributeConfig;
import com.cool.store.request.bonus.BonusRuleProductConfig;
import com.cool.store.request.bonus.BonusRuleReceivedConfig;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* <p>
* 奖金发放规则VO
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Data
public class BonusRuleVO {
@ApiModelProperty("id")
private Long id;
@ApiModelProperty("规则类型1-实收 2-新品销售")
private Integer type;
@ApiModelProperty("门店id")
private String storeId;
@ApiModelProperty("门店编码")
private String storeNum;
@ApiModelProperty("门店名称")
private String storeName;
@ApiModelProperty("生效开始年月")
private Date startDate;
@ApiModelProperty("生效结束年月")
private Date endDate;
@ApiModelProperty("日均实收小于等于该值不发放奖金(实收必填)")
private BigDecimal receivedStart;
@ApiModelProperty("实收奖励规则配置(实收必填)")
private List<BonusRuleReceivedConfig> receivedConfigs;
@ApiModelProperty("新品销售奖金规则配置(新品销售必填)")
private List<BonusRuleProductConfig> productConfigs;
@ApiModelProperty("分配规则")
private List<BonusRuleDistributeConfig> distributeConfigs;
@ApiModelProperty("是否启用0否1是")
private Integer enable;
@ApiModelProperty("上月日均实收")
private BigDecimal receivedDailyLast;
}

View File

@@ -0,0 +1,33 @@
package com.cool.store.vo.bonus;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* <p>
* 门店实收员工VO
* </p>
*
* @author wangff
* @since 2026/4/22
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EmployeeBonusVO {
@ApiModelProperty("员工id")
private String rewardUserId;
@ApiModelProperty("员工名称")
private String rewardUserName;
@ApiModelProperty("奖励比例")
private BigDecimal rewardRatio;
@ApiModelProperty("金额")
private BigDecimal receivedAmount;
}

View File

@@ -3,6 +3,7 @@ package com.cool.store.service;
import com.cool.store.dto.StoreDTO;
import com.cool.store.dto.StoreNameDTO;
import com.cool.store.dto.store.AuthStoreUserDTO;
import com.cool.store.dto.store.StoreUserDTO;
import com.cool.store.dto.store.StoreUserPositionDTO;
import com.cool.store.request.store.StoreListRequest;
import com.cool.store.response.MiniShopsResponse;
@@ -38,6 +39,11 @@ public interface StoreService {
List<AuthStoreUserDTO> authStoreUser(List<String> storeIdList, String positionType);
/**
* 同标品方法一致authStoreUser方法会查询出运营顾问等角色
*/
List<AuthStoreUserDTO> authStoreUserV2(List<String> storeIdList, String positionType);
List<AuthStoreUserDTO> getStorePositionUserList(List<String> storeIds,
List<String> positionIds,
List<String> nodePersonList,
@@ -51,4 +57,9 @@ public interface StoreService {
Boolean handleStoreLogLai(Integer flag,String specialStoreCode);
/**
* 获取门店人员的店内职位信息
*/
List<StoreUserDTO> getStoreUserPositionList(String storeId, String userName);
}

View File

@@ -0,0 +1,43 @@
package com.cool.store.service;
import com.cool.store.request.storeopen.StoreMonthRevenueRequest;
import com.cool.store.request.storeopen.StoreRecipeDailySalesRequest;
import com.cool.store.request.storeopen.StoreRecipesRequest;
import com.cool.store.response.storeopen.StoreMonthRevenueResponse;
import com.cool.store.response.storeopen.StoreRecipeDailySalesResponse;
import com.cool.store.response.storeopen.StoreRecipesResponse;
import java.util.List;
/**
* 第三方门店开放数据服务接口
*
* @author wangff
* @since 2026/4/20
*/
public interface ThirdStoreOpenDataService {
/**
* 查询门店月营收数据
*
* @param request 请求参数
* @return 月营收数据列表
*/
List<StoreMonthRevenueResponse> getMonthRevenue(StoreMonthRevenueRequest request);
/**
* 查询门店菜品日销量数据
*
* @param request 请求参数
* @return 菜品日销量数据列表
*/
List<StoreRecipeDailySalesResponse> getRecipeDailySales(StoreRecipeDailySalesRequest request);
/**
* 查询门店菜品种类
*
* @param request 请求参数
* @return 菜品种类列表
*/
List<StoreRecipesResponse> getRecipes(StoreRecipesRequest request);
}

View File

@@ -0,0 +1,156 @@
package com.cool.store.service.bonus;
import com.cool.store.entity.bonus.BonusDistributionRuleDO;
import com.cool.store.request.bonus.*;
import com.cool.store.response.storeopen.StoreRecipesResponse;
import com.cool.store.vo.bonus.*;
import com.github.pagehelper.PageInfo;
import java.math.BigDecimal;
import java.util.List;
/**
* <p>
* 奖金发放规则服务类
* </p>
*
* @author wangff
* @since 2026/4/20
*/
public interface BonusService {
/**
* 新增规则
*/
String addRule(BonusRuleAddRequest request, String createUserId);
/**
* 编辑规则
*/
Boolean updateRule(BonusRuleUpdateRequest request, String updateUserId);
/**
* 启用规则
*/
Boolean enableRule(BonusRuleEnableRequest request);
/**
* 规则详情
*/
BonusRuleVO getRuleDetail(Long ruleId);
/**
* 规则列表查询
*/
PageInfo<BonusRuleListVO> getList(BonusRuleQueryRequest request);
/**
* 实收实算
*/
BonusReceivedComputeVO receivedCompute(BonusReceivedComputeRequest request);
/**
* 新品销售实算
*/
BonusProductComputeVO productCompute(BonusProductComputeRequest request);
/**
* 处理单个实收规则
*/
void processReceivedRule(BonusDistributionRuleDO rule, String payMonth);
/**
* 处理单个新品销售规则
*/
void processNewProductRule(BonusDistributionRuleDO rule, String payDate);
/**
* 处理员工奖励明细
*/
void processEmployeeDetail(String payMonth);
/**
* 门店实收奖金发放列表
*/
PageInfo<BonusReceivedStoreListVO> getReceivedStoreList(BonusReceivedStoreQueryRequest request);
/**
* 门店实收奖金详情
*/
BonusReceivedStoreDetailVO getReceivedStoreDetail(Long id);
/**
* 员工实收奖金发放列表
*/
PageInfo<BonusReceivedEmployeeListVO> getReceivedEmployeeList(BonusReceivedEmployeeQueryRequest request);
/**
* 员工实收奖金详情
*/
BonusReceivedStoreDetailVO getReceivedEmployeeDetail(Long id);
/**
* 门店新品销售奖金发放列表-门店
*/
PageInfo<BonusProductStoreListVO> getNewProductStoreList(BonusProductQueryRequest request);
/**
* 门店新品销售奖金详情
*/
BonusProductStoreDetailVO getNewProductStoreDetail(BonusProductMonthlyQueryRequest request);
/**
* 门店新品销售奖金发放列表-菜品
*/
PageInfo<BonusProductRecipeListVO> getNewProductRecipeList(BonusProductQueryRequest request);
/**
* 门店新品销售奖金发放详情-菜品
*/
PageInfo<BonusProductRecipeDetailVO> getNewProductRecipeDetail(BonusProductRecipeQueryRequest request);
/**
* 门店新品销售奖金发放列表-员工
*/
PageInfo<BonusProductEmployeeListVO> getNewProductEmployeeList(BonusProductEmployeeQueryRequest request);
/**
* 门店新品销售奖金发放详情-员工
*/
BonusProductStoreDetailVO getNewProductEmployeeDetail(BonusProductMonthlyQueryRequest request);
/**
* 门店新品销售奖金方法列表-菜品+员工
*/
PageInfo<BonusProductRecipeEmployeeListVO> getNewProductRecipeEmployeeList(BonusProductEmployeeQueryRequest request);
/**
* 门店新品销售奖金发放详情-菜品+员工
*/
PageInfo<BonusProductRecipeEmployeeDetailVO> getNewProductRecipeEmployeeDetail(BonusProductRecipeEmployeeQueryRequest request);
/**
* 员工奖金明细
*/
PageInfo<BonusEmployeeDetailVO> getEmployeeMonthlyDetail(BonusProductEmployeeQueryRequest request);
/**
* 删除月度实收数据
*/
void deleteMonthlyReceived(BonusDistributionRuleDO ruleDO, String payMonth);
/**
* 删除每日新品销售数据
*/
void deleteMonthlyNewProduct(BonusDistributionRuleDO ruleDO, String payDate);
/**
* 查询门店菜品种类
*/
List<StoreRecipesResponse> getRecipes(String storeId);
/**
* 查询上月日均实收
*/
BigDecimal receivedDailyLast(String storeId);
}

View File

@@ -0,0 +1,898 @@
package com.cool.store.service.bonus.impl;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.lang.Pair;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.core.utils.StringUtils;
import com.cool.store.dao.StoreDao;
import com.cool.store.dao.bonus.*;
import com.cool.store.entity.StoreDO;
import com.cool.store.entity.bonus.*;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.bonus.*;
import com.cool.store.request.storeopen.StoreMonthRevenueRequest;
import com.cool.store.request.storeopen.StoreRecipeDailySalesRequest;
import com.cool.store.request.storeopen.StoreRecipesRequest;
import com.cool.store.response.storeopen.StoreMonthRevenueResponse;
import com.cool.store.response.storeopen.StoreRecipeDailySalesResponse;
import com.cool.store.response.storeopen.StoreRecipesResponse;
import com.cool.store.service.ThirdStoreOpenDataService;
import com.cool.store.service.bonus.BonusService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.poi.DateUtils;
import com.cool.store.vo.bonus.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
* <p>
* 奖金发放规则服务实现类
* </p>
*
* @author wangff
* @since 2026/4/20
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class BonusServiceImpl implements BonusService {
private final BonusDistributionRuleDAO ruleDAO;
private final ThirdStoreOpenDataService storeOpenDataService;
private final BonusReceivedStoreDAO receivedStoreDAO;
private final StoreDao storeDao;
private final BonusEmployeeRewardDetailDAO rewardDetailDAO;
private final BonusReceivedEmployeeDAO receivedEmployeeDAO;
private final BonusNewProductEmployeeDAO newProductEmployeeDAO;
private final BonusNewProductStoreDAO newProductStoreDAO;
private final BonusNewProductRecipeDAO newProductRecipeDAO;
private final BonusNewProductRecipeEmployeeDAO newProductRecipeEmployeeDAO;
@Override
public String addRule(BonusRuleAddRequest request, String createUserId) {
if (ruleDAO.existOverlap(request.getStoreId(), request.getType(), request.getStartDate(), request.getEndDate())) {
throw new ServiceException(ErrorCodeEnum.BONUS_EXIST_OVERLAP_RULE);
}
BonusDistributionRuleDO ruleDO = BeanUtil.toBean(request, BonusDistributionRuleDO.class);
ruleDO.setCreateUserId(createUserId);
ruleDAO.addRule(ruleDO);
return ruleDO.getId().toString();
}
@Override
public Boolean updateRule(BonusRuleUpdateRequest request, String updateUserId) {
BonusDistributionRuleDO ruleDO = ruleDAO.getById(request.getId());
if (Objects.isNull(ruleDO)) {
throw new ServiceException(ErrorCodeEnum.BONUS_RULE_NOT_EXIST);
}
if (ruleDAO.existOverlap(ruleDO.getStoreId(), ruleDO.getType(), request.getStartDate(), request.getEndDate())) {
throw new ServiceException(ErrorCodeEnum.BONUS_EXIST_OVERLAP_RULE);
}
BigDecimal rewardRatio = request.getDistributeConfigs().stream()
.map(BonusRuleDistributeConfig::getRewardRatio)
.reduce(BigDecimal.ZERO, BigDecimal::add);
if (rewardRatio.compareTo(BigDecimal.valueOf(100)) > 0) {
throw new ServiceException(ErrorCodeEnum.BONUS_DISTRIBUTE_RATIO_OVER_100);
}
JSONObject config = new JSONObject();
if (ruleDO.getType().equals(1)) {
for (BonusRuleReceivedConfig receivedConfig : request.getReceivedConfigs()) {
if (receivedConfig.getGt().compareTo(receivedConfig.getLe()) >= 0) {
throw new ServiceException(ErrorCodeEnum.BONUS_RULE_CONFIG_ERROR);
}
}
config.put("receivedStart", request.getReceivedStart());
config.put("receivedConfigs", request.getReceivedConfigs());
} else {
// 校验是否有相同菜品
Map<String, List<BonusRuleProductConfig>> group = CollStreamUtil.groupByKey(request.getProductConfigs(), BonusRuleProductConfig::getRecipeNo);
for (List<BonusRuleProductConfig> value : group.values()) {
if (value.size() > 1) {
throw new ServiceException(ErrorCodeEnum.BONUS_PRODUCT_CONFIG_DUPLICATE);
}
}
config.put("productConfigs", request.getProductConfigs());
}
BonusDistributionRuleDO updateRule = BonusDistributionRuleDO.builder()
.id(request.getId())
.startDate(request.getStartDate())
.endDate(request.getEndDate())
.bonusConfig(config.toJSONString())
.distributeConfig(JSONObject.toJSONString(request.getDistributeConfigs()))
.updateUserId(updateUserId)
.build();
return ruleDAO.updateByPrimaryKeySelective(updateRule);
}
@Override
public Boolean enableRule(BonusRuleEnableRequest request) {
BonusDistributionRuleDO ruleDO = ruleDAO.getById(request.getId());
if (Objects.isNull(ruleDO)) {
throw new ServiceException(ErrorCodeEnum.BONUS_RULE_NOT_EXIST);
}
if (request.getEnable().equals(1) && ruleDAO.existOverlap(ruleDO.getStoreId(), ruleDO.getType(), ruleDO.getStartDate(), ruleDO.getEndDate())) {
throw new ServiceException(ErrorCodeEnum.BONUS_EXIST_OVERLAP_RULE);
}
// 校验两个规则是否配置
if (StringUtils.isBlank(ruleDO.getBonusConfig()) || StringUtils.isBlank(ruleDO.getDistributeConfig())) {
throw new ServiceException(ErrorCodeEnum.BONUS_RULE_NOT_CONFIG);
}
BonusDistributionRuleDO updateRule = new BonusDistributionRuleDO();
updateRule.setId(request.getId());
updateRule.setEnable(request.getEnable());
return ruleDAO.updateByPrimaryKeySelective(updateRule);
}
@Override
public BonusRuleVO getRuleDetail(Long ruleId) {
BonusDistributionRuleDO ruleDO = ruleDAO.getById(ruleId);
BonusRuleVO vo = BeanUtil.toBean(ruleDO, BonusRuleVO.class);
if (Objects.nonNull(vo)) {
JSONObject bonusConfig = JSONObject.parseObject(ruleDO.getBonusConfig());
BeanUtil.copyPropertiesIgnoreId(bonusConfig, vo);
vo.setDistributeConfigs(JSONObject.parseArray(ruleDO.getDistributeConfig(), BonusRuleDistributeConfig.class));
StoreDO storeDO = storeDao.getEffectiveByStoreId(vo.getStoreId());
if (Objects.nonNull(storeDO)) {
vo.setStoreNum(storeDO.getStoreNum());
vo.setStoreName(storeDO.getStoreName());
}
if (ruleDO.getType().equals(1)) {
// 查询上月日均实收
String lastMonth = LocalDate.now().minusMonths(1).format(DateTimeFormatter.ofPattern("yyyy-MM"));
StoreMonthRevenueRequest request = new StoreMonthRevenueRequest();
request.setStoreNum(storeDO.getStoreNum());
request.setStartDate(lastMonth);
request.setEndDate(lastMonth);
List<StoreMonthRevenueResponse> monthRevenue = storeOpenDataService.getMonthRevenue(request);
if (CollectionUtils.isNotEmpty(monthRevenue)) {
StoreMonthRevenueResponse storeMonthRevenueResponse = monthRevenue.get(0);
vo.setReceivedDailyLast(Objects.nonNull(storeMonthRevenueResponse.getReceivedAmountDaily()) ? storeMonthRevenueResponse.getReceivedAmountDaily() : BigDecimal.ZERO);
}
}
}
return vo;
}
@Override
public PageInfo<BonusRuleListVO> getList(BonusRuleQueryRequest request) {
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<BonusDistributionRuleDO> list = ruleDAO.getList(request.getStoreNumOrName(), request.getType(), request.getEnable(), request.getStoreId());
PageInfo<BonusRuleListVO> page = BeanUtil.toPage(new PageInfo<>(list), BonusRuleListVO.class);
fillBasicField(page.getList());
return page;
}
@Override
public BonusReceivedComputeVO receivedCompute(BonusReceivedComputeRequest request) {
if (Objects.isNull(request.getBusinessDays()) || request.getBusinessDays().equals(0)) {
List<BonusComputeUserVO> detail = CollStreamUtil.toList(request.getDistributeConfigs(), v -> new BonusComputeUserVO(BigDecimal.ZERO, v.getRewardUserId(), v.getRewardUserName()));
log.info("日营业天数为0");
return new BonusReceivedComputeVO(BigDecimal.ZERO, BigDecimal.ZERO, detail);
}
BigDecimal businessDays = BigDecimal.valueOf(request.getBusinessDays());
BigDecimal receivedDaily = request.getReceivedMonthly().divide(businessDays, 2, RoundingMode.HALF_UP);
if (receivedDaily.compareTo(request.getReceivedStart()) <= 0) {
List<BonusComputeUserVO> detail = CollStreamUtil.toList(request.getDistributeConfigs(), v -> new BonusComputeUserVO(BigDecimal.ZERO, v.getRewardUserId(), v.getRewardUserName()));
log.info("日均实收小于等于该值起始值");
return new BonusReceivedComputeVO(receivedDaily, BigDecimal.ZERO, detail);
}
BigDecimal amountTotal = BigDecimal.ZERO;
for (BonusRuleReceivedConfig config : request.getReceivedConfigs()) {
BigDecimal lowerBound = config.getGt();
BigDecimal upperBound = config.getLe();
if (lowerBound.compareTo(upperBound) >= 0) {
throw new ServiceException(ErrorCodeEnum.BONUS_RULE_CONFIG_ERROR);
}
if (receivedDaily.compareTo(lowerBound) > 0) {
BigDecimal intervalAmount;
if (upperBound == null || receivedDaily.compareTo(upperBound) <= 0) {
intervalAmount = receivedDaily.subtract(lowerBound);
} else {
intervalAmount = upperBound.subtract(lowerBound);
}
// 计算该区间的奖金:区间金额 × 奖励比例% × 月度营业天数
BigDecimal intervalBonus = intervalAmount.multiply(config.getRewardRatio())
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP)
.multiply(businessDays);
amountTotal = amountTotal.add(intervalBonus);
}
}
BigDecimal finalAmountTotal = amountTotal;
List<BonusComputeUserVO> detail = CollStreamUtil.toList(request.getDistributeConfigs(), d -> {
BigDecimal userAmount = finalAmountTotal.multiply(d.getRewardRatio())
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
return new BonusComputeUserVO(userAmount, d.getRewardUserId(), d.getRewardUserName());
});
return new BonusReceivedComputeVO(receivedDaily, amountTotal, detail);
}
@Override
public BonusProductComputeVO productCompute(BonusProductComputeRequest request) {
if (CollectionUtils.isEmpty(request.getRecipeSales())
|| CollectionUtils.isEmpty(request.getProductConfigs())
|| CollectionUtils.isEmpty(request.getDistributeConfigs())) {
log.info("参数为空");
return null;
}
Map<String, Integer> recipeSaleMap = CollStreamUtil.toMap(request.getRecipeSales(), BonusProductRecipeCompute::getRecipeNo, BonusProductRecipeCompute::getSalesVolume);
Map<String, BigDecimal> employeeAmount = new HashMap<>();
List<BonusProductRecipeComputeVO> resultRecipes = new ArrayList<>();
for (BonusRuleProductConfig productConfig : request.getProductConfigs()) {
BonusProductRecipeComputeVO recipeVO = BeanUtil.toBean(productConfig, BonusProductRecipeComputeVO.class);
Integer salesVolume = recipeSaleMap.getOrDefault(productConfig.getRecipeNo(), 0);
recipeVO.setSalesVolume(salesVolume);
BigDecimal salesVolumeBig = BigDecimal.valueOf(salesVolume).setScale(2, RoundingMode.HALF_UP);
BigDecimal basicRewardAmount = salesVolume.compareTo(productConfig.getMinStandardNum()) < 0
? BigDecimal.ZERO
: salesVolumeBig.multiply(productConfig.getRewardAmount());
BigDecimal excessRewardAmount = salesVolume.compareTo(productConfig.getExcessStandardNum()) < 0
? BigDecimal.ZERO
: salesVolumeBig.subtract(BigDecimal.valueOf(productConfig.getExcessStandardNum()))
.multiply(productConfig.getExcessAmount());
recipeVO.setBasicRewardAmount(basicRewardAmount);
recipeVO.setExcessRewardAmount(excessRewardAmount);
List<BonusComputeUserVO> detail = CollStreamUtil.toList(request.getDistributeConfigs(), d -> {
BigDecimal basic = basicRewardAmount.multiply(d.getRewardRatio())
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
BigDecimal excess = excessRewardAmount.multiply(d.getRewardRatio())
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
BigDecimal rewardAmount = basic.add(excess);
employeeAmount.compute(d.getRewardUserId(), (k, v) -> {
if (v == null) {
v = BigDecimal.ZERO;
}
return v.add(rewardAmount);
});
return new BonusComputeUserVO(rewardAmount, d.getRewardUserId(), d.getRewardUserName(), basic, excess, d.getRewardRatio());
});
recipeVO.setDetail(detail);
resultRecipes.add(recipeVO);
}
Map<String, String> userMap = CollStreamUtil.toMap(request.getDistributeConfigs(), BonusRuleDistributeConfig::getRewardUserId, BonusRuleDistributeConfig::getRewardUserName);
List<BonusComputeUserVO> detail = CollStreamUtil.toList(employeeAmount.entrySet(), v -> new BonusComputeUserVO(v.getValue(), v.getKey(), userMap.get(v.getKey())));
return new BonusProductComputeVO(resultRecipes, detail);
}
@Override
public void processReceivedRule(BonusDistributionRuleDO rule, String payMonth) {
String storeId = rule.getStoreId();
// 检查是否已统计过
if (receivedStoreDAO.existsByRuleIdAndPayDate(rule.getId(), payMonth)) {
log.info("规则已统计过, ruleId: {}, payMonth: {}", rule.getId(), payMonth);
return;
}
// 获取门店编号
StoreDO store = storeDao.getEffectiveByStoreId(storeId);
if (store == null) {
log.warn("门店不存在, storeId: {}", storeId);
return;
}
String storeNum = store.getStoreNum();
// 解析规则配置
JSONObject bonusConfig = JSONObject.parseObject(rule.getBonusConfig());
BigDecimal receivedStart = bonusConfig.getBigDecimal("receivedStart");
List<BonusRuleReceivedConfig> receivedConfigs = bonusConfig.getJSONArray("receivedConfigs")
.toJavaList(BonusRuleReceivedConfig.class);
List<BonusRuleDistributeConfig> distributeConfigs = JSONObject.parseArray(rule.getDistributeConfig(), BonusRuleDistributeConfig.class);
// 调用API获取门店月营收数据
StoreMonthRevenueRequest request = new StoreMonthRevenueRequest();
request.setStoreNum(storeNum);
request.setStartDate(payMonth);
request.setEndDate(payMonth);
List<StoreMonthRevenueResponse> revenueList = storeOpenDataService.getMonthRevenue(request);
if (org.apache.commons.collections4.CollectionUtils.isEmpty(revenueList)) {
log.warn("门店月营收数据为空, storeNum: {}", storeNum);
return;
}
StoreMonthRevenueResponse revenue = revenueList.get(0);
// 计算奖金
BonusReceivedComputeRequest computeRequest = new BonusReceivedComputeRequest();
computeRequest.setReceivedMonthly(revenue.getReceivedAmount());
computeRequest.setBusinessDays(revenue.getBusinessDays());
computeRequest.setReceivedStart(receivedStart);
computeRequest.setReceivedConfigs(receivedConfigs);
computeRequest.setDistributeConfigs(distributeConfigs);
BonusReceivedComputeVO computeVO = receivedCompute(computeRequest);
// 处理门店实收数据
saveReceivedData(rule, payMonth, revenue, computeVO, distributeConfigs);
// 处理员工奖金明细
processEmployeeDetail(payMonth);
}
@Override
public void processNewProductRule(BonusDistributionRuleDO rule, String payDate) {
String storeId = rule.getStoreId();
// 检查是否已统计过
if (newProductStoreDAO.existsByRuleIdAndPayDate(rule.getId(), payDate)) {
log.info("规则已统计过, ruleId: {}, payDate: {}", rule.getId(), payDate);
return;
}
// 获取门店编号
StoreDO store = storeDao.getEffectiveByStoreId(storeId);
if (store == null) {
log.warn("门店不存在, storeId: {}", storeId);
return;
}
String storeNum = store.getStoreNum();
// 解析规则配置
JSONObject bonusConfig = JSONObject.parseObject(rule.getBonusConfig());
List<BonusRuleProductConfig> productConfigs = bonusConfig.getJSONArray("productConfigs")
.toJavaList(BonusRuleProductConfig.class);
List<BonusRuleDistributeConfig> distributeConfigs = JSONObject.parseArray(rule.getDistributeConfig(), BonusRuleDistributeConfig.class);
// 调用API获取门店菜品日销量数据
StoreRecipeDailySalesRequest request = new StoreRecipeDailySalesRequest();
request.setStoreNum(storeNum);
request.setStartDate(payDate);
request.setEndDate(payDate);
List<StoreRecipeDailySalesResponse> salesList = storeOpenDataService.getRecipeDailySales(request);
if (CollectionUtils.isEmpty(salesList)) {
log.warn("门店菜品日销量数据为空, storeNum: {}", storeNum);
return;
}
// 构建销量请求
List<BonusProductRecipeCompute> recipeSales = CollStreamUtil.toList(salesList, v -> new BonusProductRecipeCompute(v.getRecipeNo(), v.getSales()));
// 计算奖金
BonusProductComputeRequest computeRequest = new BonusProductComputeRequest();
computeRequest.setRecipeSales(recipeSales);
computeRequest.setProductConfigs(productConfigs);
computeRequest.setDistributeConfigs(distributeConfigs);
BonusProductComputeVO computeVO = productCompute(computeRequest);
// 入库
saveNewProductData(rule, payDate, computeVO, productConfigs, distributeConfigs);
}
@Override
public void processEmployeeDetail(String payMonth) {
// 查询门店员工实收数据
List<BonusReceivedEmployeeDO> receiveList = receivedEmployeeDAO.getMonthlyStatisticsGroupByStore(payMonth);
// 查询门店员工新品销售数据
List<BonusNewProductEmployeeDO> productList = newProductEmployeeDAO.getMonthlyStatisticsGroupByStore(payMonth);
// 将实收数据转为 Map<storeId, Map<rewardUserId, BonusReceivedEmployeeDO>>
Map<String, Map<String, BonusReceivedEmployeeDO>> receiveMap = receiveList.stream()
.collect(Collectors.groupingBy(
BonusReceivedEmployeeDO::getStoreId,
Collectors.toMap(
BonusReceivedEmployeeDO::getRewardUserId,
v -> v,
(v1, v2) -> v1
)
));
// 将新品数据转为 Map<storeId, Map<rewardUserId, BonusNewProductEmployeeDO>>
Map<String, Map<String, BonusNewProductEmployeeDO>> productMap = productList.stream()
.collect(Collectors.groupingBy(
BonusNewProductEmployeeDO::getStoreId,
Collectors.toMap(
BonusNewProductEmployeeDO::getRewardUserId,
v -> v,
(v1, v2) -> v1
)
));
Set<Pair<String, String>> allStoreUser = new HashSet<>();
allStoreUser.addAll(CollStreamUtil.toList(receiveList, v -> Pair.of(v.getStoreId(), v.getRewardUserId())));
allStoreUser.addAll(CollStreamUtil.toList(productList, v -> Pair.of(v.getStoreId(), v.getRewardUserId())));
Date payDate = DateUtils.strToDate(payMonth, "yyyy-MM");
List<BonusEmployeeRewardDetailDO> detailList = CollStreamUtil.toList(allStoreUser, v -> {
String storeId = v.getKey();
String rewardUserId = v.getValue();
BonusEmployeeRewardDetailDO detailDO = new BonusEmployeeRewardDetailDO();
detailDO.setStoreId(storeId);
detailDO.setPayDate(payDate);
detailDO.setRewardUserId(rewardUserId);
BonusReceivedEmployeeDO receive = receiveMap.getOrDefault(storeId, Collections.emptyMap()).get(rewardUserId);
BonusNewProductEmployeeDO product = productMap.getOrDefault(storeId, Collections.emptyMap()).get(rewardUserId);
detailDO.setReceivedAmount(Objects.nonNull(receive) ? receive.getReceivedAmount() : BigDecimal.ZERO);
detailDO.setNewProjectAmount(Objects.nonNull(product) ? product.getRewardAmount() : BigDecimal.ZERO);
if (Objects.nonNull(receive)) {
detailDO.setRewardUserName(receive.getRewardUserName());
}
if (Objects.nonNull(product)) {
detailDO.setRewardUserName(product.getRewardUserName());
}
return detailDO;
});
if (CollectionUtils.isNotEmpty(detailList)) {
rewardDetailDAO.insertOrUpdateBatch(detailList);
}
}
/**
* 入库实收奖金数据
*/
private void saveReceivedData(BonusDistributionRuleDO rule, String payMonth,
StoreMonthRevenueResponse revenue, BonusReceivedComputeVO computeVO,
List<BonusRuleDistributeConfig> distributeConfigs) {
Date payDate = DateUtils.strToDate(payMonth, "yyyy-MM");
// 实收门店数据
BonusReceivedStoreDO receivedStoreDO = new BonusReceivedStoreDO();
receivedStoreDO.setRuleId(rule.getId());
receivedStoreDO.setStoreId(rule.getStoreId());
receivedStoreDO.setPayDate(payDate);
receivedStoreDO.setReceivedMonthly(revenue.getReceivedAmount());
receivedStoreDO.setBusinessDays(revenue.getBusinessDays());
receivedStoreDO.setReceivedDaily(revenue.getReceivedAmountDaily());
receivedStoreDO.setReceivedDailyLast(revenue.getReceivedAmountDailyLastMonth());
receivedStoreDO.setAmountTotal(computeVO.getAmountTotal());
receivedStoreDAO.insert(receivedStoreDO);
// 实收门店员工数据
List<BonusReceivedEmployeeDO> employeeList = new ArrayList<>();
for (BonusComputeUserVO userVO : computeVO.getDetail()) {
BonusReceivedEmployeeDO employeeDO = new BonusReceivedEmployeeDO();
employeeDO.setReceivedStoreId(receivedStoreDO.getId());
employeeDO.setRuleId(rule.getId());
employeeDO.setStoreId(rule.getStoreId());
employeeDO.setPayDate(payDate);
// 查找分配比例
BonusRuleDistributeConfig config = findDistributeConfigByName(distributeConfigs, userVO.getRewardUserId());
if (config != null) {
employeeDO.setRewardRatio(config.getRewardRatio());
employeeDO.setRewardUserId(config.getRewardUserId());
}
employeeDO.setReceivedAmount(userVO.getRewardAmount());
employeeDO.setRewardUserName(userVO.getRewardUserName());
employeeDO.setRewardUserId(userVO.getRewardUserId());
employeeList.add(employeeDO);
}
receivedEmployeeDAO.insertBatch(employeeList);
}
private BonusRuleDistributeConfig findDistributeConfigByName(List<BonusRuleDistributeConfig> distributeConfigs, String userId) {
if (org.apache.commons.collections4.CollectionUtils.isEmpty(distributeConfigs) || userId == null) {
return null;
}
return distributeConfigs.stream()
.filter(c -> c.getRewardUserId().equals(userId))
.findFirst()
.orElse(null);
}
/**
* 处理新品销售奖金数据
*/
private void saveNewProductData(BonusDistributionRuleDO rule, String payDate,
BonusProductComputeVO computeVO,
List<BonusRuleProductConfig> productConfigs,
List<BonusRuleDistributeConfig> distributeConfigs) {
Date payDateObj = DateUtils.strToDate(payDate, "yyyy-MM-dd");
// 计算总金额
BigDecimal amountTotal = computeVO.getDetail().stream()
.map(BonusComputeUserVO::getRewardAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 1. 新品销售奖金-门店
BonusNewProductStoreDO productStoreDO = new BonusNewProductStoreDO();
productStoreDO.setRuleId(rule.getId());
productStoreDO.setStoreId(rule.getStoreId());
productStoreDO.setPayDate(payDateObj);
productStoreDO.setAmountTotal(amountTotal);
newProductStoreDAO.insert(productStoreDO);
// 2. 入库新品销售奖金-员工
List<BonusNewProductEmployeeDO> employeeList = new ArrayList<>();
for (BonusComputeUserVO userVO : computeVO.getDetail()) {
BonusNewProductEmployeeDO employeeDO = new BonusNewProductEmployeeDO();
employeeDO.setProductStoreId(productStoreDO.getId());
employeeDO.setRuleId(rule.getId());
employeeDO.setStoreId(rule.getStoreId());
employeeDO.setPayDate(payDateObj);
BonusRuleDistributeConfig config = findDistributeConfigByName(distributeConfigs, userVO.getRewardUserId());
if (config != null) {
employeeDO.setRewardRatio(config.getRewardRatio());
employeeDO.setRewardUserId(config.getRewardUserId());
}
employeeDO.setRewardAmount(userVO.getRewardAmount());
employeeDO.setRewardUserName(userVO.getRewardUserName());
employeeList.add(employeeDO);
}
newProductEmployeeDAO.insertBatch(employeeList);
// 3. 新品销售奖金-菜品
List<BonusNewProductRecipeDO> recipeList = new ArrayList<>();
for (BonusProductRecipeComputeVO recipeVO : computeVO.getRecipes()) {
BonusNewProductRecipeDO recipeDO = new BonusNewProductRecipeDO();
recipeDO.setRuleId(rule.getId());
recipeDO.setStoreId(rule.getStoreId());
recipeDO.setPayDate(payDateObj);
recipeDO.setRecipeNo(recipeVO.getRecipeNo());
recipeDO.setRecipeName(recipeVO.getRecipeName());
// 查找对应的配置
BonusRuleProductConfig config = productConfigs.stream()
.filter(c -> c.getRecipeNo().equals(recipeVO.getRecipeNo()))
.findFirst().orElse(null);
if (config != null) {
recipeDO.setMinStandardNum(config.getMinStandardNum());
recipeDO.setRewardAmount(config.getRewardAmount());
recipeDO.setExcessStandardNum(config.getExcessStandardNum());
recipeDO.setExcessAmount(config.getExcessAmount());
}
recipeDO.setSalesVolume(recipeVO.getSalesVolume());
recipeDO.setBasicRewardAmount(recipeVO.getBasicRewardAmount());
recipeDO.setExcessRewardAmount(recipeVO.getExcessRewardAmount());
recipeList.add(recipeDO);
}
newProductRecipeDAO.insertBatch(recipeList);
// 4. 新品销售奖金-菜品-员工
List<BonusNewProductRecipeEmployeeDO> recipeEmployeeList = new ArrayList<>();
for (BonusProductRecipeComputeVO recipeVO : computeVO.getRecipes()) {
BonusNewProductRecipeDO savedRecipe = recipeList.stream()
.filter(r -> r.getRecipeNo().equals(recipeVO.getRecipeNo()))
.findFirst().orElse(null);
if (savedRecipe != null && CollectionUtils.isNotEmpty(recipeVO.getDetail())) {
for (BonusComputeUserVO userVO : recipeVO.getDetail()) {
BonusNewProductRecipeEmployeeDO recipeEmployeeDO = new BonusNewProductRecipeEmployeeDO();
recipeEmployeeDO.setProductRecipeId(savedRecipe.getId());
recipeEmployeeDO.setRuleId(rule.getId());
recipeEmployeeDO.setStoreId(rule.getStoreId());
recipeEmployeeDO.setPayDate(payDateObj);
recipeEmployeeDO.setRecipeNo(recipeVO.getRecipeNo());
recipeEmployeeDO.setRecipeName(recipeVO.getRecipeName());
recipeEmployeeDO.setSalesVolume(recipeVO.getSalesVolume());
// 计算基础和超额奖金
BigDecimal basicReward = userVO.getBasicRewardAmount();
BigDecimal excessReward = userVO.getExcessRewardAmount();
recipeEmployeeDO.setBasicRewardAmount(basicReward != null ? basicReward : BigDecimal.ZERO);
recipeEmployeeDO.setExcessRewardAmount(excessReward != null ? excessReward : BigDecimal.ZERO);
recipeEmployeeDO.setRewardRatio(userVO.getRewardRatio());
recipeEmployeeDO.setRewardUserName(userVO.getRewardUserName());
recipeEmployeeDO.setRewardUserId(userVO.getRewardUserId());
recipeEmployeeList.add(recipeEmployeeDO);
}
}
}
newProductRecipeEmployeeDAO.insertBatch(recipeEmployeeList);
}
@Override
public PageInfo<BonusReceivedStoreListVO> getReceivedStoreList(BonusReceivedStoreQueryRequest request) {
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<BonusReceivedStoreDO> list = receivedStoreDAO.selectListByCondition(
request.getStoreNumOrName(), request.getStartMonth(), request.getEndMonth(), request.getStoreId());
PageInfo<BonusReceivedStoreListVO> page = BeanUtil.toPage(new PageInfo<>(list), BonusReceivedStoreListVO.class);
fillBasicField(page.getList());
return page;
}
@Override
public BonusReceivedStoreDetailVO getReceivedStoreDetail(Long id) {
BonusReceivedStoreDO storeDO = receivedStoreDAO.getById(id);
if (Objects.isNull(storeDO)) {
return null;
}
BonusReceivedStoreDetailVO vo = BeanUtil.toBean(storeDO, BonusReceivedStoreDetailVO.class);
// 获取门店信息
StoreDO store = storeDao.getEffectiveByStoreId(storeDO.getStoreId());
if (Objects.nonNull(store)) {
vo.setStoreNum(store.getStoreNum());
vo.setStoreName(store.getStoreName());
}
// 获取奖金规则配置
BonusDistributionRuleDO ruleDO = ruleDAO.getById(storeDO.getRuleId());
if (Objects.nonNull(ruleDO)) {
JSONObject bonusConfig = JSONObject.parseObject(ruleDO.getBonusConfig());
BeanUtil.copyPropertiesIgnoreId(bonusConfig, vo);
}
// 获取员工本月奖金发放列表
List<BonusReceivedEmployeeDO> employeeList = receivedEmployeeDAO.selectByReceivedStoreId(id);
List<EmployeeBonusVO> employeeVOList = CollStreamUtil.toList(employeeList, e ->
new EmployeeBonusVO(e.getRewardUserId(), e.getRewardUserName(), e.getRewardRatio(), e.getReceivedAmount()));
vo.setEmployeeList(employeeVOList);
return vo;
}
@Override
public PageInfo<BonusReceivedEmployeeListVO> getReceivedEmployeeList(BonusReceivedEmployeeQueryRequest request) {
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<BonusReceivedEmployeeDO> list = receivedEmployeeDAO.selectEmployeeListByCondition(
request.getStoreNumOrName(), request.getStartMonth(), request.getEndMonth(), request.getRewardUserName(), request.getStoreId());
PageInfo<BonusReceivedEmployeeListVO> page = BeanUtil.toPage(new PageInfo<>(list), BonusReceivedEmployeeListVO.class);
if (CollectionUtils.isEmpty(list)) {
return page;
}
// 获取门店实收信息
Set<Long> receivedStoreIds = CollStreamUtil.toSet(list, BonusReceivedEmployeeDO::getReceivedStoreId);
Map<Long, BonusReceivedStoreDO> storeDOMap = receivedStoreDAO.getMapByIds(new ArrayList<>(receivedStoreIds));
// 获取门店信息
fillBasicField(page.getList());
page.getList().forEach(v -> {
// 填充门店实收信息
BonusReceivedStoreDO receivedStoreDO = storeDOMap.get(v.getReceivedStoreId());
if (Objects.nonNull(receivedStoreDO)) {
v.setReceivedMonthly(receivedStoreDO.getReceivedMonthly());
v.setBusinessDays(receivedStoreDO.getBusinessDays());
v.setReceivedDaily(receivedStoreDO.getReceivedDaily());
v.setReceivedDailyLast(receivedStoreDO.getReceivedDailyLast());
v.setAmountTotal(receivedStoreDO.getAmountTotal());
}
});
return page;
}
@Override
public BonusReceivedStoreDetailVO getReceivedEmployeeDetail(Long id) {
BonusReceivedEmployeeDO employeeDO = receivedEmployeeDAO.getById(id);
if (Objects.isNull(employeeDO)) {
return null;
}
BonusReceivedStoreDO storeDO = receivedStoreDAO.getById(employeeDO.getReceivedStoreId());
if (Objects.isNull(storeDO)) {
return null;
}
BonusReceivedStoreDetailVO vo = BeanUtil.toBean(storeDO, BonusReceivedStoreDetailVO.class);
// 获取门店信息
StoreDO store = storeDao.getEffectiveByStoreId(storeDO.getStoreId());
if (Objects.nonNull(store)) {
vo.setStoreNum(store.getStoreNum());
vo.setStoreName(store.getStoreName());
}
// 获取奖金规则配置
BonusDistributionRuleDO ruleDO = ruleDAO.getById(storeDO.getRuleId());
if (Objects.nonNull(ruleDO)) {
JSONObject bonusConfig = JSONObject.parseObject(ruleDO.getBonusConfig());
BeanUtil.copyPropertiesIgnoreId(bonusConfig, vo);
}
// 获取员工本月奖金发放列表
EmployeeBonusVO employeeVO = new EmployeeBonusVO(employeeDO.getRewardUserId(), employeeDO.getRewardUserName(), employeeDO.getRewardRatio(), employeeDO.getReceivedAmount());
vo.setEmployeeList(Collections.singletonList(employeeVO));
return vo;
}
@Override
public PageInfo<BonusProductStoreListVO> getNewProductStoreList(BonusProductQueryRequest request) {
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<BonusNewProductStoreDO> list = newProductStoreDAO.monthlyStatistics(request.getStoreNumOrName(), request.getStartDate(), request.getEndDate(), null, null);
PageInfo<BonusProductStoreListVO> page = BeanUtil.toPage(new PageInfo<>(list), BonusProductStoreListVO.class);
fillBasicField(page.getList());
return page;
}
@Override
public BonusProductStoreDetailVO getNewProductStoreDetail(BonusProductMonthlyQueryRequest request) {
if (Objects.isNull(request.getRuleId())) {
throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE, "规则id不能为空");
}
List<BonusNewProductStoreDO> list = newProductStoreDAO.monthlyStatistics(null, request.getPayDate(), request.getPayDate(), request.getStoreId(), request.getRuleId());
if (CollectionUtils.isEmpty(list)) {
return null;
}
BonusNewProductStoreDO productStoreDO = list.get(0);
BonusProductStoreDetailVO vo = new BonusProductStoreDetailVO();
BonusDistributionRuleDO ruleDO = ruleDAO.getById(productStoreDO.getRuleId());
if (Objects.nonNull(ruleDO)) {
JSONObject bonusConfig = JSONObject.parseObject(ruleDO.getBonusConfig());
BeanUtil.copyPropertiesIgnoreId(bonusConfig, vo);
}
vo.setPayDate(productStoreDO.getPayDate());
// 获取门店信息
StoreDO store = storeDao.getEffectiveByStoreId(productStoreDO.getStoreId());
if (Objects.nonNull(store)) {
vo.setStoreNum(store.getStoreNum());
vo.setStoreName(store.getStoreName());
}
// 获取发放明细列表
List<BonusNewProductEmployeeDO> employeeList = newProductEmployeeDAO.monthlyStatistics(request.getRuleId(), request.getStoreId(), request.getPayDate(), null);
List<EmployeeBonusVO> employeeVOList = CollStreamUtil.toList(employeeList, e ->
new EmployeeBonusVO(e.getRewardUserId(), e.getRewardUserName(), null, e.getRewardAmount()));
vo.setEmployeeList(employeeVOList);
return vo;
}
@Override
public PageInfo<BonusProductRecipeListVO> getNewProductRecipeList(BonusProductQueryRequest request) {
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<BonusNewProductRecipeDO> list = newProductRecipeDAO.monthlyStatistics(request.getStoreNumOrName(), request.getStartDate(), request.getEndDate(), request.getRecipeNoOrName());
PageInfo<BonusProductRecipeListVO> page = BeanUtil.toPage(new PageInfo<>(list), BonusProductRecipeListVO.class);
fillBasicField(page.getList());
return page;
}
@Override
public PageInfo<BonusProductRecipeDetailVO> getNewProductRecipeDetail(BonusProductRecipeQueryRequest request) {
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<BonusNewProductRecipeDO> list = newProductRecipeDAO.selectListByCondition(request.getStoreId(), request.getRecipeNo(), request.getStartDate(), request.getEndDate());
PageInfo<BonusProductRecipeDetailVO> page = BeanUtil.toPage(new PageInfo<>(list), BonusProductRecipeDetailVO.class);
fillBasicField(page.getList());
return page;
}
@Override
public PageInfo<BonusProductEmployeeListVO> getNewProductEmployeeList(BonusProductEmployeeQueryRequest request) {
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<BonusNewProductEmployeeDO> list = newProductEmployeeDAO.employeeMonthlyStatistics(request.getStartDate(),
request.getEndDate(), request.getStoreNumOrName(), request.getRewardUserName(), request.getStoreId());
List<BonusProductEmployeeListVO> result = CollStreamUtil.toList(list, v -> {
BonusProductEmployeeListVO vo = BeanUtil.toBean(v, BonusProductEmployeeListVO.class);
vo.setReceivedAmount(v.getRewardAmount());
return vo;
});
PageInfo<BonusProductEmployeeListVO> page = BeanUtil.toPage(new PageInfo<>(list), result);
fillBasicField(page.getList());
return page;
}
@Override
public BonusProductStoreDetailVO getNewProductEmployeeDetail(BonusProductMonthlyQueryRequest request) {
if (Objects.isNull(request.getRewardUserId())) {
throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE, "奖励人id不能为空");
}
List<BonusNewProductEmployeeDO> list = newProductEmployeeDAO.monthlyStatistics(null, request.getStoreId(), request.getPayDate(), request.getRewardUserId());
if (CollectionUtils.isEmpty(list)) {
return null;
}
BonusNewProductEmployeeDO employeeDO = list.get(0);
BonusProductStoreDetailVO vo = new BonusProductStoreDetailVO();
vo.setPayDate(request.getPayDate());
BonusDistributionRuleDO ruleDO = ruleDAO.getById(employeeDO.getRuleId());
if (Objects.nonNull(ruleDO)) {
JSONObject bonusConfig = JSONObject.parseObject(ruleDO.getBonusConfig());
BeanUtil.copyPropertiesIgnoreId(bonusConfig, vo);
}
vo.setPayDate(employeeDO.getPayDate());
// 获取门店信息
StoreDO store = storeDao.getEffectiveByStoreId(request.getStoreId());
if (Objects.nonNull(store)) {
vo.setStoreNum(store.getStoreNum());
vo.setStoreName(store.getStoreName());
}
List<EmployeeBonusVO> employeeVOList = Collections.singletonList(new EmployeeBonusVO(employeeDO.getRewardUserId(), employeeDO.getRewardUserName(), null, employeeDO.getRewardAmount()));
vo.setEmployeeList(employeeVOList);
return vo;
}
@Override
public PageInfo<BonusProductRecipeEmployeeListVO> getNewProductRecipeEmployeeList(BonusProductEmployeeQueryRequest request) {
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<BonusNewProductRecipeEmployeeDO> list = newProductRecipeEmployeeDAO.monthlyStatistics(request.getStoreNumOrName(), request.getStartDate(), request.getEndDate(), request.getRewardUserName(), request.getRecipeNoOrName());
PageInfo<BonusProductRecipeEmployeeListVO> page = BeanUtil.toPage(new PageInfo<>(list), BonusProductRecipeEmployeeListVO.class);
fillBasicField(page.getList());
return page;
}
@Override
public PageInfo<BonusProductRecipeEmployeeDetailVO> getNewProductRecipeEmployeeDetail(BonusProductRecipeEmployeeQueryRequest request) {
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<BonusNewProductRecipeEmployeeDO> list = newProductRecipeEmployeeDAO.selectListByCondition(request.getStoreId(), request.getRecipeNo(), request.getRewardUserId(), request.getStartDate(), request.getEndDate());
Set<Long> productRecipeIds = CollStreamUtil.toSet(list, BonusNewProductRecipeEmployeeDO::getProductRecipeId);
Map<Long, BonusNewProductRecipeDO> productRecipeMap = newProductRecipeDAO.getMapByIds(new ArrayList<>(productRecipeIds));
List<BonusProductRecipeEmployeeDetailVO> result = CollStreamUtil.toList(list, v -> {
BonusProductRecipeEmployeeDetailVO vo = BeanUtil.toBean(v, BonusProductRecipeEmployeeDetailVO.class);
BonusNewProductRecipeDO recipeDO = productRecipeMap.get(v.getProductRecipeId());
if (Objects.nonNull(recipeDO)) {
vo.setMinStandardNum(recipeDO.getMinStandardNum());
vo.setRewardAmount(recipeDO.getRewardAmount());
vo.setExcessStandardNum(recipeDO.getExcessStandardNum());
vo.setExcessAmount(recipeDO.getExcessAmount());
}
return vo;
});
PageInfo<BonusProductRecipeEmployeeDetailVO> page = BeanUtil.toPage(new PageInfo<>(list), result);
fillBasicField(page.getList());
return page;
}
@Override
public PageInfo<BonusEmployeeDetailVO> getEmployeeMonthlyDetail(BonusProductEmployeeQueryRequest request) {
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<BonusEmployeeRewardDetailDO> list = rewardDetailDAO.selectListByCondition(request.getStoreNumOrName(),
request.getStartDate(), request.getEndDate(), request.getRewardUserName(), request.getStoreId());
PageInfo<BonusEmployeeDetailVO> page = BeanUtil.toPage(new PageInfo<>(list), BonusEmployeeDetailVO.class);
fillBasicField(page.getList());
return page;
}
@Override
@Transactional
public void deleteMonthlyReceived(BonusDistributionRuleDO ruleDO, String payMonth) {
Date payDate = DateUtils.strToDate(payMonth, "yyyy-MM");
// 门店实收
receivedStoreDAO.deleteMonthlyReceived(ruleDO.getId(), ruleDO.getStoreId(), payDate);
// 员工
receivedEmployeeDAO.deleteMonthlyReceived(ruleDO.getId(), ruleDO.getStoreId(), payDate);
}
@Override
@Transactional
public void deleteMonthlyNewProduct(BonusDistributionRuleDO ruleDO, String payDate) {
Date payDateObj = DateUtils.strToDate(payDate, "yyyy-MM-dd");
newProductRecipeDAO.deleteDailyNewProduct(ruleDO.getId(), ruleDO.getStoreId(), payDateObj);
newProductRecipeEmployeeDAO.deleteDailyNewProduct(ruleDO.getId(), ruleDO.getStoreId(), payDateObj);
newProductEmployeeDAO.deleteDailyNewProduct(ruleDO.getId(), ruleDO.getStoreId(), payDateObj);
newProductStoreDAO.deleteDailyNewProduct(ruleDO.getId(), ruleDO.getStoreId(), payDateObj);
}
@Override
public List<StoreRecipesResponse> getRecipes(String storeId) {
StoreDO storeDO = storeDao.getEffectiveByStoreId(storeId);
if (Objects.isNull(storeDO)) {
throw new ServiceException(ErrorCodeEnum.STORE_NOT_FIND);
}
StoreRecipesRequest request = new StoreRecipesRequest();
request.setStoreNum(storeDO.getStoreNum());
return storeOpenDataService.getRecipes(request);
}
@Override
public BigDecimal receivedDailyLast(String storeId) {
StoreDO storeDO = storeDao.getEffectiveByStoreId(storeId);
if (Objects.isNull(storeDO)) {
throw new ServiceException(ErrorCodeEnum.STORE_NOT_FIND);
}
String lastMonth = LocalDate.now().minusMonths(1).format(DateTimeFormatter.ofPattern("yyyy-MM"));
StoreMonthRevenueRequest request = new StoreMonthRevenueRequest();
request.setStoreNum(storeDO.getStoreNum());
request.setStartDate(lastMonth);
request.setEndDate(lastMonth);
List<StoreMonthRevenueResponse> monthRevenue = storeOpenDataService.getMonthRevenue(request);
if (CollectionUtils.isNotEmpty(monthRevenue)) {
StoreMonthRevenueResponse storeMonthRevenueResponse = monthRevenue.get(0);
return Objects.nonNull(storeMonthRevenueResponse.getReceivedAmountDaily()) ? storeMonthRevenueResponse.getReceivedAmountDaily() : BigDecimal.ZERO;
}
return BigDecimal.ZERO;
}
private void fillBasicField(List<? extends BonusBasicVO> list) {
Set<String> storeIds = CollStreamUtil.toSet(list, BonusBasicVO::getStoreId);
Map<String, StoreDO> storeMap = storeDao.getStoreMapByStoreIds(new ArrayList<>(storeIds));
list.forEach(v -> {
StoreDO storeDO = storeMap.get(v.getStoreId());
if (Objects.nonNull(storeDO)) {
v.setStoreNum(storeDO.getStoreNum());
v.setStoreName(storeDO.getStoreName());
}
});
}
}

View File

@@ -353,6 +353,51 @@ public class StoreServiceImpl implements StoreService {
return Boolean.TRUE;
}
@Override
public List<StoreUserDTO> getStoreUserPositionList(String storeId, String userName) {
if (StrUtil.isBlank(storeId)) {
throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR.getCode(), "请选择门店后查询");
}
List<AuthStoreUserDTO> authStoreUserDTOList = this.authStoreUserV2(
Collections.singletonList(storeId), "store_inside");
if (CollectionUtils.isEmpty(authStoreUserDTOList)) {
return new ArrayList<>();
}
List<String> userIdList = ListUtils.emptyIfNull(authStoreUserDTOList)
.stream()
.map(AuthStoreUserDTO::getUserIdList)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
if (CollUtil.isEmpty(userIdList)) {
return new ArrayList<>();
}
List<StoreUserDTO> list = sysRoleMapper.userAndPositionList( userIdList, userName, "store_inside");
if (CollectionUtils.isNotEmpty(list)) {
//先去重
list = list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
new TreeSet<>(Comparator.comparing(StoreUserDTO::getUserId))), ArrayList::new));
}
Map<String, List<StoreUserDTO>> storeUserDTOMap = ListUtils.emptyIfNull(list).stream().collect(Collectors.groupingBy(k -> k.getUserId()));
List<StoreUserDTO> result = Lists.newArrayList();
for (String userId : storeUserDTOMap.keySet()) {
List<StoreUserDTO> singleUserDTOList = storeUserDTOMap.get(userId);
if (CollectionUtils.isEmpty(singleUserDTOList)) {
continue;
}
StoreUserDTO storeUserDTO = singleUserDTOList.get(0);
List<String> positionNameList = ListUtils.emptyIfNull(singleUserDTOList)
.stream().map(StoreUserDTO::getPositionName).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(positionNameList)) {
storeUserDTO.setPositionName(String.join(Constants.COMMA, positionNameList));
}
result.add(storeUserDTO);
}
return result;
}
@Override
public List<AuthStoreUserDTO> authStoreUser(List<String> storeIdList, String positionType) {
@@ -402,6 +447,55 @@ public class StoreServiceImpl implements StoreService {
.map(data -> mapAuthStoreUserDTO(regionUserAuthMappingList, allStoreUserIdList, storeUserAuthMappingList, notIncludeRegionUserAuthMappingList, data))
.collect(Collectors.toList());
}
@Override
public List<AuthStoreUserDTO> authStoreUserV2(List<String> storeIdList, String positionType) {
List<AuthStoreUserDTO> result = new ArrayList<>();
if (CollectionUtils.isEmpty(storeIdList)) {
return result;
}
//将拥有管理员角色、角色属性为全企业数据的人查询出来
List<SysRoleVO> roleUserByRoleId = sysRoleMapper.getRoleUserByRoleEnum(Role.MASTER.getRoleEnum(),positionType);
List<SysRoleVO> roleUserByRoleAuth = sysRoleMapper.getRoleUserByRoleAuth(AuthRoleEnum.ALL.getCode(),positionType);
//组合出拥有所有门店信息的人
List<String> allStoreUserIdList = getAllStoreUserIdList(roleUserByRoleId, roleUserByRoleAuth);
//查询出有门店权限配置的的人员
// 1.将门店区域切分出门店所属于的区域ID
// 2.将配置了区域的人 查询出来
// 3.将配置了门店的人 查询出来
List<StoreAreaDTO> storeAreaList = storeMapper.getStoreAreaList(storeIdList);
if (CollectionUtils.isEmpty(storeAreaList)) {
return Collections.emptyList();
}
List<String> fullAreaIdList = ListUtils.emptyIfNull(storeAreaList)
.stream()
.map(StoreAreaDTO::getAreaIdList)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
List<String> lastAreaIdList = ListUtils.emptyIfNull(storeAreaList)
.stream()
.map(StoreAreaDTO::getAreaId)
.distinct()
.collect(Collectors.toList());
//除不包含子区域的可视化范围的区域配置。
List<UserAuthMappingDO> regionUserAuthMappingList = userAuthMappingMapper.listUserAuthMappingByAuthV2(
UserAuthMappingTypeEnum.REGION.getCode(), fullAreaIdList, positionType, AuthRoleEnum.NOT_INCLUDE_SUBORDINATE.getCode());
//不包含子区域的的直属连接门店的区域下的配置(会重复一些选择了上面数据)
List<UserAuthMappingDO> notIncludeRegionUserAuthMappingList = userAuthMappingMapper.listUserAuthMappingByAuthV2(
UserAuthMappingTypeEnum.REGION.getCode(), lastAreaIdList, positionType, null);
//配置了门店的的配置
List<UserAuthMappingDO> storeUserAuthMappingList = userAuthMappingMapper.listUserAuthMappingByMappingList(
storeIdList, UserAuthMappingTypeEnum.STORE.getCode());
return ListUtils.emptyIfNull(storeAreaList)
.stream()
.map(data -> mapAuthStoreUserDTO(regionUserAuthMappingList, allStoreUserIdList, storeUserAuthMappingList, notIncludeRegionUserAuthMappingList, data))
.collect(Collectors.toList());
}
private List<String> getAllStoreUserIdList(List<SysRoleVO> roleUserByRoleId, List<SysRoleVO> roleUserByRoleAuth) {
List<String> allUserIdList= new ArrayList<>();

View File

@@ -0,0 +1,172 @@
package com.cool.store.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.storeopen.StoreMonthRevenueRequest;
import com.cool.store.request.storeopen.StoreRecipeDailySalesRequest;
import com.cool.store.request.storeopen.StoreRecipesRequest;
import com.cool.store.response.storeopen.StoreMonthRevenueResponse;
import com.cool.store.response.storeopen.StoreOpenApiResponse;
import com.cool.store.response.storeopen.StoreRecipeDailySalesResponse;
import com.cool.store.response.storeopen.StoreRecipesResponse;
import com.cool.store.service.ThirdStoreOpenDataService;
import com.cool.store.utils.StoreOpenSigner;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 第三方门店开放数据服务实现类
*
* @author wangff
* @since 2026/4/20
*/
@Service
@Slf4j
public class ThirdStoreOpenDataServiceImpl implements ThirdStoreOpenDataService {
@Value("${store.open.url}")
private String apiUrl;
@Value("${store.open.appId}")
private String appId;
@Value("${store.open.secret}")
private String secret;
@Resource
private OkHttpClient okHttpClient;
@Resource
private ObjectMapper objectMapper;
private static final String METHOD_POST = "POST";
@Override
public List<StoreMonthRevenueResponse> getMonthRevenue(StoreMonthRevenueRequest request) {
String path = "/open/v1/store/monthRevenue";
String url = apiUrl + path;
return executeApiCall(url, path, request, StoreMonthRevenueResponse.class);
}
@Override
public List<StoreRecipeDailySalesResponse> getRecipeDailySales(StoreRecipeDailySalesRequest request) {
String path = "/open/v1/store/recipeDailySales";
String url = apiUrl + path;
return executeApiCall(url, path, request, StoreRecipeDailySalesResponse.class);
}
@Override
public List<StoreRecipesResponse> getRecipes(StoreRecipesRequest request) {
String path = "/open/v1/store/recipes";
String url = apiUrl + path;
return executeApiCall(url, path, request, StoreRecipesResponse.class);
}
private <T> List<T> executeApiCall(String url, String path, Object request, Class<T> responseType) {
logRequest(url, request);
try {
String rawJsonBody = JSONObject.toJSONString(request);
Request httpRequest = buildRequest(url, path, rawJsonBody);
try (Response response = okHttpClient.newCall(httpRequest).execute()) {
String responseBody = response.body().string();
logResponse(url, response.code(), responseBody);
if (!response.isSuccessful()) {
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
"HTTP请求失败状态码: " + response.code());
}
JavaType javaType = objectMapper.getTypeFactory()
.constructParametricType(StoreOpenApiResponse.class,
objectMapper.getTypeFactory().constructCollectionType(List.class, responseType));
StoreOpenApiResponse<List<T>> apiResponse = objectMapper.readValue(responseBody, javaType);
if (apiResponse.getCode() != 200) {
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, apiResponse.getMsg());
}
return apiResponse.getData();
}
} catch (ServiceException e) {
throw e;
} catch (Exception e) {
log.error("API调用异常 - URL: {}, 错误: {}", url, e.getMessage(), e);
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "接口调用异常: " + e.getMessage());
}
}
private Request buildRequest(String url, String path, String rawJsonBody) {
String signTime = StoreOpenSigner.generateSignTime();
String signRandom = StoreOpenSigner.generateRandom(16);
String signingString = StoreOpenSigner.buildSigningString(METHOD_POST, path, rawJsonBody, signTime, signRandom);
String sign = StoreOpenSigner.sign(signingString, secret);
log.debug("签名生成 - 原始字符串: {}, 签名结果: {}", signingString, sign);
RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json"), rawJsonBody);
return new Request.Builder()
.url(url)
.post(body)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.addHeader("App-Id", appId)
.addHeader("X-ZhengXin-Sign", sign)
.addHeader("X-ZhengXin-SignTime", signTime)
.addHeader("X-ZhengXin-SignRandom", signRandom)
.build();
}
private void logRequest(String url, Object requestBody) {
if (log.isInfoEnabled()) {
try {
log.info("\n======= 请求开始 =======\n" +
"API地址: {}\n" +
"请求参数: {}\n" +
"======= 请求结束 =======",
url,
objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(requestBody));
} catch (JsonProcessingException e) {
log.warn("日志JSON序列化失败", e);
}
}
}
private void logResponse(String url, int statusCode, String responseBody) {
if (log.isInfoEnabled()) {
try {
Object json = objectMapper.readValue(responseBody, Object.class);
String prettyResponse = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(json);
log.info("\n======= 响应开始 =======\n" +
"API地址: {}\n" +
"HTTP状态码: {}\n" +
"响应内容: {}\n" +
"======= 响应结束 =======",
url, statusCode, prettyResponse);
} catch (Exception e) {
log.info("\n======= 响应开始 =======\n" +
"API地址: {}\n" +
"HTTP状态码: {}\n" +
"原始响应: {}\n" +
"======= 响应结束 =======",
url, statusCode, responseBody);
}
}
}
}

View File

@@ -0,0 +1,164 @@
package com.cool.store.controller.webb;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.request.bonus.*;
import com.cool.store.response.ResponseResult;
import com.cool.store.response.storeopen.StoreRecipesResponse;
import com.cool.store.service.bonus.BonusService;
import com.cool.store.vo.bonus.*;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* <p>
* 工资奖金发放 前端控制器
* </p>
*
* @author wangff
* @since 2026/4/21
*/
@Api(tags = "工资奖金发放")
@RestController
@RequestMapping("/pc/bonus")
@RequiredArgsConstructor
public class BonusController {
private final BonusService bonusService;
@ApiOperation("新增规则")
@PostMapping("/addRule")
public ResponseResult<String> addRule(@RequestBody @Validated BonusRuleAddRequest request) {
return ResponseResult.success(bonusService.addRule(request, CurrentUserHolder.getUserId()));
}
@ApiOperation("编辑规则")
@PostMapping("/updateRule")
public ResponseResult<Boolean> updateRule(@RequestBody @Validated BonusRuleUpdateRequest request) {
return ResponseResult.success(bonusService.updateRule(request, CurrentUserHolder.getUserId()));
}
@ApiOperation("启用规则")
@PostMapping("/enableRule")
public ResponseResult<Boolean> enableRule(@RequestBody @Validated BonusRuleEnableRequest request) {
return ResponseResult.success(bonusService.enableRule(request));
}
@ApiOperation("规则详情")
@GetMapping("/ruleDetail")
@ApiImplicitParam(name = "ruleId", value = "规则id", required = true, dataType = "Long", paramType = "query")
public ResponseResult<BonusRuleVO> getRuleDetail(@NotNull(message = "规则id不能为空") Long ruleId) {
return ResponseResult.success(bonusService.getRuleDetail(ruleId));
}
@ApiOperation("规则列表查询")
@PostMapping("/list")
public ResponseResult<PageInfo<BonusRuleListVO>> getList(@RequestBody BonusRuleQueryRequest request) {
return ResponseResult.success(bonusService.getList(request));
}
@ApiOperation("实收实算")
@PostMapping("/receivedCompute")
public ResponseResult<BonusReceivedComputeVO> receivedCompute(@RequestBody @Validated BonusReceivedComputeRequest request) {
return ResponseResult.success(bonusService.receivedCompute(request));
}
@ApiOperation("新品销售实算")
@PostMapping("/productCompute")
public ResponseResult<BonusProductComputeVO> productCompute(@RequestBody @Validated BonusProductComputeRequest request) {
return ResponseResult.success(bonusService.productCompute(request));
}
@ApiOperation("门店实收奖金发放列表")
@PostMapping("/receivedStoreList")
public ResponseResult<PageInfo<BonusReceivedStoreListVO>> getReceivedStoreList(@RequestBody BonusReceivedStoreQueryRequest request) {
return ResponseResult.success(bonusService.getReceivedStoreList(request));
}
@ApiOperation("门店实收奖金详情")
@GetMapping("/receivedStoreDetail")
@ApiImplicitParam(name = "id", value = "门店实收奖金id", required = true, dataType = "Long", paramType = "query")
public ResponseResult<BonusReceivedStoreDetailVO> getReceivedStoreDetail(@NotNull(message = "id不能为空") Long id) {
return ResponseResult.success(bonusService.getReceivedStoreDetail(id));
}
@ApiOperation("员工实收奖金发放列表")
@PostMapping("/receivedEmployeeList")
public ResponseResult<PageInfo<BonusReceivedEmployeeListVO>> getReceivedEmployeeList(@RequestBody BonusReceivedEmployeeQueryRequest request) {
return ResponseResult.success(bonusService.getReceivedEmployeeList(request));
}
@ApiOperation("员工实收奖金详情")
@GetMapping("/receivedEmployeeDetail")
@ApiImplicitParam(name = "id", value = "员工实收奖金id", required = true, dataType = "Long", paramType = "query")
public ResponseResult<BonusReceivedStoreDetailVO> getReceivedEmployeeDetail(@NotNull(message = "id不能为空") Long id) {
return ResponseResult.success(bonusService.getReceivedEmployeeDetail(id));
}
@ApiOperation("新品销售奖金发放-门店列表")
@PostMapping("/newProductStoreList")
public ResponseResult<PageInfo<BonusProductStoreListVO>> getNewProductStoreList(@RequestBody BonusProductQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductStoreList(request));
}
@ApiOperation("新品销售奖金-门店详情")
@PostMapping("/newProductStoreDetail")
@ApiImplicitParam(name = "id", value = "门店新品销售奖金id", required = true, dataType = "Long", paramType = "query")
public ResponseResult<BonusProductStoreDetailVO> getNewProductStoreDetail(@RequestBody @Validated BonusProductMonthlyQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductStoreDetail(request));
}
@ApiOperation("新品销售奖金-菜品列表")
@PostMapping("/newProductRecipeList")
public ResponseResult<PageInfo<BonusProductRecipeListVO>> getNewProductRecipeList(@RequestBody BonusProductQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductRecipeList(request));
}
@ApiOperation("新品销售奖金-菜品详情")
@PostMapping("/newProductRecipeDetail")
public ResponseResult<PageInfo<BonusProductRecipeDetailVO>> getNewProductRecipeDetail(@RequestBody @Validated BonusProductRecipeQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductRecipeDetail(request));
}
@ApiOperation("新品销售奖金-员工列表")
@PostMapping("/newProductEmployeeList")
public ResponseResult<PageInfo<BonusProductEmployeeListVO>> getNewProductEmployeeList(@RequestBody BonusProductEmployeeQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductEmployeeList(request));
}
@ApiOperation("新品销售奖金-员工详情")
@PostMapping("/newProductEmployeeDetail")
public ResponseResult<BonusProductStoreDetailVO> getNewProductEmployeeDetail(@RequestBody @Validated BonusProductMonthlyQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductEmployeeDetail(request));
}
@ApiOperation("新品销售奖金-菜品+员工列表")
@PostMapping("/newProductRecipeEmployeeList")
public ResponseResult<PageInfo<BonusProductRecipeEmployeeListVO>> getNewProductRecipeEmployeeList(@RequestBody BonusProductEmployeeQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductRecipeEmployeeList(request));
}
@ApiOperation("新品销售奖金-菜品+员工详情")
@PostMapping("/newProductRecipeEmployeeDetail")
public ResponseResult<PageInfo<BonusProductRecipeEmployeeDetailVO>> getNewProductRecipeEmployeeDetail(@RequestBody @Validated BonusProductRecipeEmployeeQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductRecipeEmployeeDetail(request));
}
@ApiOperation("员工奖金明细")
@PostMapping("/employeeBonusDetail")
public ResponseResult<PageInfo<BonusEmployeeDetailVO>> getEmployeeBonusDetail(@RequestBody BonusProductEmployeeQueryRequest request) {
return ResponseResult.success(bonusService.getEmployeeMonthlyDetail(request));
}
@ApiOperation("门店菜品列表")
@GetMapping("/recipeList")
public ResponseResult<List<StoreRecipesResponse>> getRecipeList(@RequestParam @NotNull(message = "门店id不能为空") String storeId) {
return ResponseResult.success(bonusService.getRecipes(storeId));
}
}

View File

@@ -2,6 +2,7 @@ package com.cool.store.controller.webb;
import com.cool.store.common.PageBasicInfo;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.dto.store.StoreUserDTO;
import com.cool.store.request.store.StoreListRequest;
import com.cool.store.request.UserStoreRequest;
import com.cool.store.response.MiniShopsResponse;
@@ -15,6 +16,8 @@ import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* <p>
* PC门店 前端控制器
@@ -42,4 +45,9 @@ public class PCStoreController {
return ResponseResult.success(storeService.getAuthStoreList(request));
}
@ApiOperation("门店人员列表")
@GetMapping("/storeUserPositionList")
public ResponseResult<List<StoreUserDTO>> getStoreUserPositionList(String storeId, String userName) {
return ResponseResult.success(storeService.getStoreUserPositionList(storeId, userName));
}
}

View File

@@ -1,8 +1,10 @@
package com.cool.store.controller.webb;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.annotation.Debounce;
import com.cool.store.constants.CommonConstants;
import com.cool.store.dao.*;
import com.cool.store.dao.bonus.BonusDistributionRuleDAO;
import com.cool.store.dao.fees.WalletPayInfoDAO;
import com.cool.store.dto.*;
import com.cool.store.dto.contract.ContractCallbackDTO;
@@ -13,11 +15,9 @@ import com.cool.store.dto.xgj.XgjPartnerPageDTO;
import com.cool.store.dto.wallet.*;
import com.cool.store.dto.xgj.XgjPayResultDTO;
import com.cool.store.entity.*;
import com.cool.store.entity.bonus.BonusDistributionRuleDO;
import com.cool.store.entity.fees.WalletPayInfoDO;
import com.cool.store.enums.DownSystemTypeEnum;
import com.cool.store.enums.FranchiseBrandEnum;
import com.cool.store.enums.MessageEnum;
import com.cool.store.enums.SMSMsgEnum;
import com.cool.store.enums.*;
import com.cool.store.enums.point.ShopSubStageStatusEnum;
import com.cool.store.enums.wechat.WechatTemplateEnum;
import com.cool.store.handler.WeChatHandler;
@@ -31,6 +31,9 @@ import com.cool.store.request.bigdata.ProfitDataRequest;
import com.cool.store.request.close.store.CloseStoreApplyRequest;
import com.cool.store.request.huoma.ShopBasicInfoRequest;
import com.cool.store.request.oppty.*;
import com.cool.store.request.storeopen.StoreMonthRevenueRequest;
import com.cool.store.request.storeopen.StoreRecipeDailySalesRequest;
import com.cool.store.request.storeopen.StoreRecipesRequest;
import com.cool.store.request.wallet.*;
import com.cool.store.request.xgj.PushFranchiseFeeRequest;
import com.cool.store.request.xgj.*;
@@ -43,7 +46,11 @@ import com.cool.store.response.huoma.ShopBaseInfoResponse;
import com.cool.store.response.oppty.CityResponse;
import com.cool.store.response.oppty.OpportunityDetailResponse;
import com.cool.store.response.oppty.OpportunityInfoPageResponse;
import com.cool.store.response.storeopen.StoreMonthRevenueResponse;
import com.cool.store.response.storeopen.StoreRecipeDailySalesResponse;
import com.cool.store.response.storeopen.StoreRecipesResponse;
import com.cool.store.service.*;
import com.cool.store.service.bonus.BonusService;
import com.cool.store.service.close.CloseStoreService;
import com.cool.store.service.fees.WalletPayInfoService;
import com.cool.store.service.impl.CommonService;
@@ -138,6 +145,65 @@ public class PCTestController {
@Resource
WalletPayInfoService walletPayInfoService;
@Resource
ThirdStoreOpenDataService thirdStoreOpenDataService;
@Resource
BonusService bonusService;
@Resource
BonusDistributionRuleDAO bonusRuleDAO;
@PostMapping("/processReceivedRule")
@Debounce(timeMs = 10000, diffUser = false)
public ResponseResult<Boolean> processReceivedRule(Long ruleId, String payMonth) {
BonusDistributionRuleDO ruleDO = bonusRuleDAO.getById(ruleId);
if (Objects.isNull(ruleDO)) {
return ResponseResult.fail(ErrorCodeEnum.BONUS_RULE_NOT_EXIST);
}
// 删除所有实收数据
bonusService.deleteMonthlyReceived(ruleDO, payMonth);
bonusService.processReceivedRule(ruleDO, payMonth);
return ResponseResult.success(true);
}
@PostMapping("/processNewProductRule")
@Debounce(timeMs = 10000, diffUser = false)
public ResponseResult<Boolean> processNewProductRule(Long ruleId, String payDate) {
BonusDistributionRuleDO ruleDO = bonusRuleDAO.getById(ruleId);
if (Objects.isNull(ruleDO)) {
return ResponseResult.fail(ErrorCodeEnum.BONUS_RULE_NOT_EXIST);
}
bonusService.deleteMonthlyNewProduct(ruleDO, payDate);
bonusService.processNewProductRule(ruleDO, payDate);
return ResponseResult.success(true);
}
@PostMapping("/dailyNewProductBonus")
public ResponseResult<Boolean> dailyNewProductBonus() {
xxlJobHandler.dailyNewProductBonus();
return ResponseResult.success(true);
}
@PostMapping("/monthlyReceivedBonus")
public ResponseResult<Boolean> monthlyReceivedBonus() {
xxlJobHandler.monthlyReceivedBonus();
return ResponseResult.success(true);
}
@PostMapping("/getMonthRevenue")
public ResponseResult<List<StoreMonthRevenueResponse>> getMonthRevenue(@RequestBody StoreMonthRevenueRequest request) {
return ResponseResult.success(thirdStoreOpenDataService.getMonthRevenue(request));
}
@PostMapping("/getRecipeDailySales")
public ResponseResult<List<StoreRecipeDailySalesResponse>> getRecipeDailySales(@RequestBody StoreRecipeDailySalesRequest request) {
return ResponseResult.success(thirdStoreOpenDataService.getRecipeDailySales(request));
}
@PostMapping("/getRecipes")
public ResponseResult<List<StoreRecipesResponse>> getRecipes(@RequestBody StoreRecipesRequest request) {
return ResponseResult.success(thirdStoreOpenDataService.getRecipes(request));
}
@PostMapping("/walletReceiptRePush")
public ResponseResult<Boolean> walletReceiptRePush(Long id) {
walletPayInfoService.rePushReceipt(id);

View File

@@ -0,0 +1,174 @@
package com.cool.store.controller.webc;
import com.cool.store.context.PartnerUserHolder;
import com.cool.store.request.bonus.*;
import com.cool.store.response.ResponseResult;
import com.cool.store.response.storeopen.StoreRecipesResponse;
import com.cool.store.service.bonus.BonusService;
import com.cool.store.vo.bonus.*;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.List;
/**
* <p>
* Mini工资奖金发放
* </p>
*
* @author wangff
* @since 2026/4/23
*/
@Api(tags = "Mini工资奖金发放")
@RestController
@RequestMapping("/mini/bonus")
@RequiredArgsConstructor
@Valid
public class MiniBonusController {
private final BonusService bonusService;
@ApiOperation("新增规则")
@PostMapping("/addRule")
public ResponseResult<String> addRule(@RequestBody @Validated BonusRuleAddRequest request) {
return ResponseResult.success(bonusService.addRule(request, PartnerUserHolder.getUser().getPartnerId()));
}
@ApiOperation("编辑规则")
@PostMapping("/updateRule")
public ResponseResult<Boolean> updateRule(@RequestBody @Validated BonusRuleUpdateRequest request) {
return ResponseResult.success(bonusService.updateRule(request, PartnerUserHolder.getUser().getPartnerId()));
}
@ApiOperation("启用规则")
@PostMapping("/enableRule")
public ResponseResult<Boolean> enableRule(@RequestBody @Validated BonusRuleEnableRequest request) {
return ResponseResult.success(bonusService.enableRule(request));
}
@ApiOperation("规则详情")
@GetMapping("/ruleDetail")
@ApiImplicitParam(name = "ruleId", value = "规则id", required = true, dataType = "Long", paramType = "query")
public ResponseResult<BonusRuleVO> getRuleDetail(@NotNull(message = "规则id不能为空") Long ruleId) {
return ResponseResult.success(bonusService.getRuleDetail(ruleId));
}
@ApiOperation("规则列表查询")
@PostMapping("/list")
public ResponseResult<PageInfo<BonusRuleListVO>> getList(@RequestBody BonusRuleQueryRequest request) {
return ResponseResult.success(bonusService.getList(request));
}
@ApiOperation("实收实算")
@PostMapping("/receivedCompute")
public ResponseResult<BonusReceivedComputeVO> receivedCompute(@RequestBody @Validated BonusReceivedComputeRequest request) {
return ResponseResult.success(bonusService.receivedCompute(request));
}
@ApiOperation("新品销售实算")
@PostMapping("/productCompute")
public ResponseResult<BonusProductComputeVO> productCompute(@RequestBody @Validated BonusProductComputeRequest request) {
return ResponseResult.success(bonusService.productCompute(request));
}
@ApiOperation("门店实收奖金发放列表")
@PostMapping("/receivedStoreList")
public ResponseResult<PageInfo<BonusReceivedStoreListVO>> getReceivedStoreList(@RequestBody BonusReceivedStoreQueryRequest request) {
return ResponseResult.success(bonusService.getReceivedStoreList(request));
}
@ApiOperation("门店实收奖金详情")
@GetMapping("/receivedStoreDetail")
@ApiImplicitParam(name = "id", value = "门店实收奖金id", required = true, dataType = "Long", paramType = "query")
public ResponseResult<BonusReceivedStoreDetailVO> getReceivedStoreDetail(@NotNull(message = "id不能为空") Long id) {
return ResponseResult.success(bonusService.getReceivedStoreDetail(id));
}
@ApiOperation("员工实收奖金发放列表")
@PostMapping("/receivedEmployeeList")
public ResponseResult<PageInfo<BonusReceivedEmployeeListVO>> getReceivedEmployeeList(@RequestBody BonusReceivedEmployeeQueryRequest request) {
return ResponseResult.success(bonusService.getReceivedEmployeeList(request));
}
@ApiOperation("员工实收奖金详情")
@GetMapping("/receivedEmployeeDetail")
@ApiImplicitParam(name = "id", value = "员工实收奖金id", required = true, dataType = "Long", paramType = "query")
public ResponseResult<BonusReceivedStoreDetailVO> getReceivedEmployeeDetail(@NotNull(message = "id不能为空") Long id) {
return ResponseResult.success(bonusService.getReceivedEmployeeDetail(id));
}
@ApiOperation("新品销售奖金发放-门店列表")
@PostMapping("/newProductStoreList")
public ResponseResult<PageInfo<BonusProductStoreListVO>> getNewProductStoreList(@RequestBody BonusProductQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductStoreList(request));
}
@ApiOperation("新品销售奖金-门店详情")
@PostMapping("/newProductStoreDetail")
@ApiImplicitParam(name = "id", value = "门店新品销售奖金id", required = true, dataType = "Long", paramType = "query")
public ResponseResult<BonusProductStoreDetailVO> getNewProductStoreDetail(@RequestBody @Validated BonusProductMonthlyQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductStoreDetail(request));
}
@ApiOperation("新品销售奖金-菜品列表")
@PostMapping("/newProductRecipeList")
public ResponseResult<PageInfo<BonusProductRecipeListVO>> getNewProductRecipeList(@RequestBody BonusProductQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductRecipeList(request));
}
@ApiOperation("新品销售奖金-菜品详情")
@PostMapping("/newProductRecipeDetail")
public ResponseResult<PageInfo<BonusProductRecipeDetailVO>> getNewProductRecipeDetail(@RequestBody @Validated BonusProductRecipeQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductRecipeDetail(request));
}
@ApiOperation("新品销售奖金-员工列表")
@PostMapping("/newProductEmployeeList")
public ResponseResult<PageInfo<BonusProductEmployeeListVO>> getNewProductEmployeeList(@RequestBody BonusProductEmployeeQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductEmployeeList(request));
}
@ApiOperation("新品销售奖金-员工详情")
@PostMapping("/newProductEmployeeDetail")
public ResponseResult<BonusProductStoreDetailVO> getNewProductEmployeeDetail(@RequestBody @Validated BonusProductMonthlyQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductEmployeeDetail(request));
}
@ApiOperation("新品销售奖金-菜品+员工列表")
@PostMapping("/newProductRecipeEmployeeList")
public ResponseResult<PageInfo<BonusProductRecipeEmployeeListVO>> getNewProductRecipeEmployeeList(@RequestBody BonusProductEmployeeQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductRecipeEmployeeList(request));
}
@ApiOperation("新品销售奖金-菜品+员工详情")
@PostMapping("/newProductRecipeEmployeeDetail")
public ResponseResult<PageInfo<BonusProductRecipeEmployeeDetailVO>> getNewProductRecipeEmployeeDetail(@RequestBody @Validated BonusProductRecipeEmployeeQueryRequest request) {
return ResponseResult.success(bonusService.getNewProductRecipeEmployeeDetail(request));
}
@ApiOperation("员工奖金明细")
@PostMapping("/employeeBonusDetail")
public ResponseResult<PageInfo<BonusEmployeeDetailVO>> getEmployeeBonusDetail(@RequestBody BonusProductEmployeeQueryRequest request) {
return ResponseResult.success(bonusService.getEmployeeMonthlyDetail(request));
}
@ApiOperation("门店菜品列表")
@GetMapping("/recipeList")
public ResponseResult<List<StoreRecipesResponse>> getRecipeList(@RequestParam @NotNull(message = "门店id不能为空") String storeId) {
return ResponseResult.success(bonusService.getRecipes(storeId));
}
@ApiOperation("门店上月日均实收")
@GetMapping("/receivedDailyLast")
public ResponseResult<BigDecimal> getReceivedDailyLast(@RequestParam @NotBlank(message = "门店id不能为空") String storeId) {
return ResponseResult.success(bonusService.receivedDailyLast(storeId));
}
}

View File

@@ -0,0 +1,35 @@
package com.cool.store.controller.webc;
import com.cool.store.dto.store.StoreUserDTO;
import com.cool.store.response.ResponseResult;
import com.cool.store.service.StoreService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
* Mini门店 前端控制器
* </p>
*
* @author wangff
* @since 2026/4/24
*/
@Api(tags = "mini门店")
@RestController
@RequestMapping("/mini/stores")
@RequiredArgsConstructor
public class MiniStoreController {
private final StoreService storeService;
@ApiOperation("门店人员列表")
@GetMapping("/storeUserPositionList")
public ResponseResult<List<StoreUserDTO>> getStoreUserPositionList(String storeId, String userName) {
return ResponseResult.success(storeService.getStoreUserPositionList(storeId, userName));
}
}

View File

@@ -4,11 +4,13 @@ import cn.hutool.core.collection.CollStreamUtil;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.CommonConstants;
import com.cool.store.dao.*;
import com.cool.store.dao.bonus.BonusDistributionRuleDAO;
import com.cool.store.dao.tp.TpApplyFormDAO;
import com.cool.store.dao.wallet.WalletTradeDAO;
import com.cool.store.dto.*;
import com.cool.store.dto.store.StoreOrderTimeDTO;
import com.cool.store.entity.*;
import com.cool.store.entity.bonus.BonusDistributionRuleDO;
import com.cool.store.entity.tp.TpApplyFormDO;
import com.cool.store.entity.wallet.WalletTradeDO;
import com.cool.store.enums.*;
@@ -27,6 +29,7 @@ import com.cool.store.request.tp.TpApplyQueryRequest;
import com.cool.store.request.close.store.CloseStoreApplyRequest;
import com.cool.store.response.bigdata.LatestOrderDateResponse;
import com.cool.store.service.*;
import com.cool.store.service.bonus.BonusService;
import com.cool.store.service.close.CloseStoreRefundService;
import com.cool.store.service.close.CloseStoreService;
import com.cool.store.service.fees.WalletPayInfoService;
@@ -50,6 +53,7 @@ import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@@ -139,6 +143,14 @@ public class XxlJobHandler {
SplitOrderService splitOrderService;
@Resource
WithdrawApplicationService withdrawApplicationService;
@Resource
BonusDistributionRuleDAO ruleDAO;
@Resource
BonusService bonusService;
private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
/**
@@ -756,4 +768,90 @@ public class XxlJobHandler {
}
log.info("------end withdrawUpdate------");
}
/**
* 每月统计上一个月门店的实收数据并入库
* 建议每月1日凌晨执行
*/
@XxlJob("monthlyReceivedBonus")
public void monthlyReceivedBonus() {
MDCUtils.put(CommonConstants.REQUEST_ID, UUID.randomUUID().toString());
log.info("------start monthlyReceivedBonus------");
// 计算上一个月
LocalDate lastMonth = LocalDate.now().minusMonths(1);
String payMonth = lastMonth.format(MONTH_FORMATTER);
log.info("统计月份: {}", payMonth);
try {
// 获取类型为1实收的启用规则列表
int pageNum = 1, pageSize = CommonConstants.BATCH_SIZE;
boolean hasNext = true;
while (hasNext) {
PageHelper.startPage(pageNum, pageSize);
List<BonusDistributionRuleDO> rules = ruleDAO.getEnabledRulesByTypeAndMonth(1, payMonth);
if (CollectionUtils.isEmpty(rules)) {
break;
}
hasNext = rules.size() >= pageSize;
// 按门店分组处理
for (BonusDistributionRuleDO rule : rules) {
try {
log.info("处理门店:{}, ruleId;{}", rule.getStoreId(), rule.getId());
bonusService.processReceivedRule(rule, payMonth);
} catch (Exception e) {
log.error("处理实收规则失败, ruleId: {}, storeId: {}", rule.getId(), rule.getStoreId(), e);
}
}
pageNum++;
}
log.info("------end monthlyReceivedBonus------");
} catch (Exception e) {
log.error("monthlyReceivedBonus执行失败", e);
XxlJobHelper.handleFail("执行失败: " + e.getMessage());
}
}
/**
* 每天统计前一天的新品销售数据并入库
* 建议每天凌晨执行
*/
@XxlJob("dailyNewProductBonusJob")
public void dailyNewProductBonus() {
MDCUtils.put(CommonConstants.REQUEST_ID, UUID.randomUUID().toString());
log.info("------start dailyNewProductBonus------");
// 计算前一天
LocalDate yesterday = LocalDate.now().minusDays(1);
String payDate = yesterday.format(DATE_FORMATTER);
String payMonth = yesterday.format(MONTH_FORMATTER);
log.info("统计日期: {}", payDate);
try {
// 获取类型为2新品销售的启用规则列表
int pageNum = 1, pageSize = CommonConstants.BATCH_SIZE;
boolean hasNext = true;
while (hasNext) {
PageHelper.startPage(pageNum, pageSize);
List<BonusDistributionRuleDO> rules = ruleDAO.getEnabledRulesByTypeAndMonth(2, payMonth);
if (CollectionUtils.isEmpty(rules)) {
break;
}
hasNext = rules.size() >= pageSize;
// 按门店分组处理
for (BonusDistributionRuleDO rule : rules) {
try {
log.info("处理门店:{}, ruleId;{}", rule.getStoreId(), rule.getId());
bonusService.processNewProductRule(rule, payDate);
} catch (Exception e) {
log.error("处理新品销售规则失败, ruleId: {}, storeId: {}", rule.getId(), rule.getStoreId(), e);
}
}
}
log.info("------end dailyNewProductBonus------");
} catch (Exception e) {
log.error("dailyNewProductBonus执行失败", e);
XxlJobHelper.handleFail("执行失败: " + e.getMessage());
}
}
}

View File

@@ -178,4 +178,9 @@ wallet.api.yzt.key=360155690205317
cool.api.rsa.private.key=MIIEpQIBAAKCAQEA0erPAWesjkp9J4htmfCyqKS9npmT9dW3KqWTfb4c7x/QBUtKuokWOO0XikHd4bGUa9kl+twSv/5A3kYz1B9eg6wRuDJoads+G5U7rVQjzdoUtLaf3lNXkuSehl4uHUPQfNa6vcmvzraXPxJjEpYzj9WZh7uJqq2oSgw42H1qdbFCXSaE5BwsOb+2vZXjzh4RO10Sy3Qb1UqGsoZoxVzrtDeEctCjrecFyQr96L2UtYa4NTxSTfu4rgObrwIOMvqqnLsXEzK/rd6kIHYjkZYQCOa48AedWp2YKQ7Ldclj+VMLnXvl42J9exVkbs++8k3P5sI9fdZX4Ey2RBjnSoAo/QIDAQABAoIBACbBGi8I+CE77M+13wAu4RkD8xL7CQc3ic2ojGqIRPi7r5CuphD6mpzvXqtyfhd7DKr9h8bAxwBlnQ28ObjVgsI96/aM7dxvMs/uVPpqwIJyWuTDG5A05EPVC9REQnC6Mp09mnPL7rZz3Mfy6dIGY2YQWfwmWiPl1B45k+wZ+WPZPI0JVnvRzM881kf4aAhEAt08i9VoihylwVAjWIPmLuhf6ZcqI5q8iUsjfO22wZJsudVTCA/dsJdNxv+1RDKeYnSLJL79cZQcodqEhFqTy6vnn2dMsaHH7dpphU27barxUjeL482SR7kFfMqEXn5sltRn/3ep+3sf4Ph2vMtoZeECgYEA6gXzEtT9ZOeAMp4BRGmfNZ0TQLprPPVSwudz/uUBE4j/vyhfXkh9p7hqwyoxN+Z8b65yINvx8yP6hge6ek/MyAwBCZyfIRxZAPZu1eEGoYKl391ubFt2EIVqrN2DtAvzHMr5B/E2VHBq6AJm/rERFX5oKsg6zHS9tPLhgGnWVd0CgYEA5aFWOrtiqZJlp1MHQ4OeWBJatBSynkORdxCW7ic0CKbkYus0NSz1SsvskpbnfEXNB53x98qJxRhSopg/DC4m7XqxjSf9lY3HH4Y/9907olj33yGAnLWC88GivVndt577u/XhYRCk33vOQ3GoibEdjnpMOkWmOfwYG/FsRWWQvaECgYEA1N2siEisZIgel+wZAv2AD+hchtgKi1wqd5bIb+Yl4HsRBfPXK4+MnG6mzfcm5c4FCiEHNtRZc+waCKgm+vJzNtOUbgXEyP1cCAAgOPOCcI7CCqsDshRPhB+XNL4Y+kCUVnBZrNu/q3bGB1uIC8tL2t0sKx4OPcNCe8EhVQjwKRECgYEA4uothdhKRPtwDIsVsHfN74Yjr7SMVay7gIcaPrjqyGnzYnS+oJWOx50AaFNK6Rko5JAF3jF9NxE0B4yfMPAic6Y88hpEkpcJ4HMPn2Y1WdbFCu/WYgVUJICCys6VNLCcXj85umtyIY38Y9VbEMW/SV49GZBeFQqy4FoP/fvBrkECgYEAnfjTDYwgdmJdsUqyNzAocwcJXG2rVtYc7Txrl0TltcwuJmgoSywdzyOP2R9+NZsfoxWDzG0/yr15ApMvUcnnTwHN/8bGQ9SLatFLKqS4EtdwDKKS1JvNbs7V1myQGpt7jbShZOI0e6Fs4xP8ujxsLeGgiq9mZrS9UdRj5XKDoVM=
cool.api.rsa.public.key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0erPAWesjkp9J4htmfCyqKS9npmT9dW3KqWTfb4c7x/QBUtKuokWOO0XikHd4bGUa9kl+twSv/5A3kYz1B9eg6wRuDJoads+G5U7rVQjzdoUtLaf3lNXkuSehl4uHUPQfNa6vcmvzraXPxJjEpYzj9WZh7uJqq2oSgw42H1qdbFCXSaE5BwsOb+2vZXjzh4RO10Sy3Qb1UqGsoZoxVzrtDeEctCjrecFyQr96L2UtYa4NTxSTfu4rgObrwIOMvqqnLsXEzK/rd6kIHYjkZYQCOa48AedWp2YKQ7Ldclj+VMLnXvl42J9exVkbs++8k3P5sI9fdZX4Ey2RBjnSoAo/QIDAQAB
wallet.api.rsa.public.key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvU5WUX5MaZhS4MRfZ5OeqmSxTgjNi64SEwTiDYS++DRHRFTEguk1g5AbiW3l9eEdATeVk0WX+T6ZIIa2do3bQOKhlMtRwWMWQIucjGa7ySOCuicvnCD2HAQ2EThfqQdSpAW5UpcyodrhcyUkuevBA4fQQ06k9lB4FjqWtao2+aYFIPFPu8Wu28KI/9QIMLI02Q1YY3duJ67QW4EM4I2oS0t3sWJeZtIJPRHFWW1EaLJz2FdbJJq+z6D2p++9pmkHsvdnktUUO+nPL3PCLtxGYxEwr/AqTYR/1yXfkVWe3nHXc+qvRt967X1hDHC+gEPJItr7kUk3pQTGBv9kNu75DwIDAQAB
wallet.org.id=140732221567301
wallet.org.id=140732221567301
store.open.url=https://zhengxin.zhidiansoft.com:5943
store.open.appId=289704779317445
store.open.appKey=IGSAEQoakR2HEaYx
store.open.secret=aPsA99K1obFeFm3m

View File

@@ -176,4 +176,9 @@ liePin.secretKey=dns6x4f1p14a36u4t22xvteppmz07ir2
liePin.aesSecretKey=_nkULTpkBHHZeWgQ
liePin.baseUrl=https://open-xhopen-qa53.qa.xunhou.cn
liePin.tenantId=12833
liePin.mobile=13345565081
liePin.mobile=13345565081
store.open.url=https://zhengxin.zhidiansoft.com:5943
store.open.appId=289704779317445
store.open.appKey=IGSAEQoakR2HEaYx
store.open.secret=aPsA99K1obFeFm3m

View File

@@ -173,4 +173,9 @@ wallet.api.yzt.key=375393764171845
cool.api.rsa.private.key=MIIEoQIBAAKCAQEAleyT39qxm9Vi4d3f/pF4yI3EATtLlP870dFfk5Rwj1MEM4OVTUeoBrld5GwTARQYzuyZETTZPh9taFCVtLFVsQv4waTqDf/7vnfBbvrTZ2mvZv6H/M6BTQnTx5UmOIP1RsA933ce7v/hmG/DlMaHU3JVC840Ae1q7uJZ2yA6+r6aAGdTGMSH4oQ+U9omJOJbgbuti9DsBuGDDKZ1uMhrWW/l4El5y2Qdu/71wIQuI08kPegmuGl4+FLRJ2OnoGsp+BRXKpFbN0fq0YwPQhjzSHsKg64qimmzRRr5Ewd+4w1/27dJ6mopQd4zvf7+VQ4wEZgATTe/hjBw1njOOBD/WQIDAQABAoIBACSFU0ZSEzbXRbWoo0JzdF1Cb28vXwuGGy/S1XnxTHQVcG4ODSYcoPk2WYFltEFsgFiTuPvAiHUCGdgx3S39jtbIiEm/nwZXB5+Ps46RykKkM4ae1UiHk2bNUIoLMprMxkh8VvYjIeVtbqp/+0A4FkoFDWOJURDxIT3c5K+ky8k9mKz59SiOkNoiayPQTEjzZPgKSsT64286PGmE9v4BlpyxQ1bLXeZaQGAkQ7YVtU5XJgbMM86hgmFlTcHVMGeMoQvJTfcsLlRg8ucX/zzBTHR7fZP6i5OJl5CYLbzHbTyHN9KRYDYv066SvbGLNa+4NO2cY+L6NehiwAkkFxSGKkMCgYEAoVgEjOqLyL1CpeaW7ckWQSbcae0a6J61b6meCkRaKrwcWi7ut9OfmvkCae2qsMsHQlitFM8blrnhtJxMt3EhWKYHI1seZto6YR0mzEEz5IVM3OStIZN7RY4Fg6AyB0C5Gure3GgGHaSs5J8AbCpJyLjTWuOdcnThgHHe4Mw2dGsCgYEA7eF0TpAbdYn8xjqNEgeRSSXYpwtRQ1zrpH0b1KQBxx/fvoZPzWG0SYIi6eYV5bxV5EDnCKlXXFD3ztMfThPFUGt8hHAG6CKpsiVNvYDVhAzXN18JQJtRQRO/4S0f42C8os87ToL1nlM83c8hegrsGO+JnoTzKf8KkpYqTNrvrEsCf1HuYGEuuc02TqHwdrRJaQOsuEESJpf6ACiz+Y09KIyK+drR+mdfD62ixZcFGaitcQJABaSLh3cC7ZrJxCtjR4u8w+MwYj/Ykcy/APS4J6HkDyQc+84RFog7lpFAyCbmtxj0LDfAm1pyRVnTZGOJFe7X7Hw7GbkFoX2YVZXSHdUCgYEA6rCuYPxIOxSicKg/mfQhYLuYHmZKDF3WlnhgRtBweJZ31q8IeKbWild8PqukGv5O910ZEzCPYiL3+fPNROi4mPkS5k7oYYohRgMLydUb0qYghx6aMEWMStpDStOMTHaaZT5zUqhdz5Br0qKScqfn+0oIyn58sYhQVAMXRLAUGjUCgYAYiuiTme9S9gSt1pZrDbPxXlbVm6PjlkP/OKrmBj5gq8iYeKzmYKp66UKFo6ZeeRcKiXLWdQS0i0rKBPux8kmfIwbrfbuYAVGE0GmUdEMNsBQvEjxpwo3afyB5F70tdnm4EBo0qeqJxuBK8DLpBFka2yfzEo/3Z6i0X/XqIwq/7A==
cool.api.rsa.public.key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAleyT39qxm9Vi4d3f/pF4yI3EATtLlP870dFfk5Rwj1MEM4OVTUeoBrld5GwTARQYzuyZETTZPh9taFCVtLFVsQv4waTqDf/7vnfBbvrTZ2mvZv6H/M6BTQnTx5UmOIP1RsA933ce7v/hmG/DlMaHU3JVC840Ae1q7uJZ2yA6+r6aAGdTGMSH4oQ+U9omJOJbgbuti9DsBuGDDKZ1uMhrWW/l4El5y2Qdu/71wIQuI08kPegmuGl4+FLRJ2OnoGsp+BRXKpFbN0fq0YwPQhjzSHsKg64qimmzRRr5Ewd+4w1/27dJ6mopQd4zvf7+VQ4wEZgATTe/hjBw1njOOBD/WQIDAQAB
wallet.api.rsa.public.key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvU5WUX5MaZhS4MRfZ5OeqmSxTgjNi64SEwTiDYS++DRHRFTEguk1g5AbiW3l9eEdATeVk0WX+T6ZIIa2do3bQOKhlMtRwWMWQIucjGa7ySOCuicvnCD2HAQ2EThfqQdSpAW5UpcyodrhcyUkuevBA4fQQ06k9lB4FjqWtao2+aYFIPFPu8Wu28KI/9QIMLI02Q1YY3duJ67QW4EM4I2oS0t3sWJeZtIJPRHFWW1EaLJz2FdbJJq+z6D2p++9pmkHsvdnktUUO+nPL3PCLtxGYxEwr/AqTYR/1yXfkVWe3nHXc+qvRt967X1hDHC+gEPJItr7kUk3pQTGBv9kNu75DwIDAQAB
wallet.org.id=420289242456261
wallet.org.id=420289242456261
store.open.url=https://zhengxin.zhidiansoft.com:5943
store.open.appId=289704779317445
store.open.appKey=IGSAEQoakR2HEaYx
store.open.secret=aPsA99K1obFeFm3m

View File

@@ -178,4 +178,9 @@ wallet.url=https://api.dev.wenmatech.com:443
wallet.api.yzt.key=360155690205317
cool.api.rsa.private.key=MIIEpQIBAAKCAQEA0erPAWesjkp9J4htmfCyqKS9npmT9dW3KqWTfb4c7x/QBUtKuokWOO0XikHd4bGUa9kl+twSv/5A3kYz1B9eg6wRuDJoads+G5U7rVQjzdoUtLaf3lNXkuSehl4uHUPQfNa6vcmvzraXPxJjEpYzj9WZh7uJqq2oSgw42H1qdbFCXSaE5BwsOb+2vZXjzh4RO10Sy3Qb1UqGsoZoxVzrtDeEctCjrecFyQr96L2UtYa4NTxSTfu4rgObrwIOMvqqnLsXEzK/rd6kIHYjkZYQCOa48AedWp2YKQ7Ldclj+VMLnXvl42J9exVkbs++8k3P5sI9fdZX4Ey2RBjnSoAo/QIDAQABAoIBACbBGi8I+CE77M+13wAu4RkD8xL7CQc3ic2ojGqIRPi7r5CuphD6mpzvXqtyfhd7DKr9h8bAxwBlnQ28ObjVgsI96/aM7dxvMs/uVPpqwIJyWuTDG5A05EPVC9REQnC6Mp09mnPL7rZz3Mfy6dIGY2YQWfwmWiPl1B45k+wZ+WPZPI0JVnvRzM881kf4aAhEAt08i9VoihylwVAjWIPmLuhf6ZcqI5q8iUsjfO22wZJsudVTCA/dsJdNxv+1RDKeYnSLJL79cZQcodqEhFqTy6vnn2dMsaHH7dpphU27barxUjeL482SR7kFfMqEXn5sltRn/3ep+3sf4Ph2vMtoZeECgYEA6gXzEtT9ZOeAMp4BRGmfNZ0TQLprPPVSwudz/uUBE4j/vyhfXkh9p7hqwyoxN+Z8b65yINvx8yP6hge6ek/MyAwBCZyfIRxZAPZu1eEGoYKl391ubFt2EIVqrN2DtAvzHMr5B/E2VHBq6AJm/rERFX5oKsg6zHS9tPLhgGnWVd0CgYEA5aFWOrtiqZJlp1MHQ4OeWBJatBSynkORdxCW7ic0CKbkYus0NSz1SsvskpbnfEXNB53x98qJxRhSopg/DC4m7XqxjSf9lY3HH4Y/9907olj33yGAnLWC88GivVndt577u/XhYRCk33vOQ3GoibEdjnpMOkWmOfwYG/FsRWWQvaECgYEA1N2siEisZIgel+wZAv2AD+hchtgKi1wqd5bIb+Yl4HsRBfPXK4+MnG6mzfcm5c4FCiEHNtRZc+waCKgm+vJzNtOUbgXEyP1cCAAgOPOCcI7CCqsDshRPhB+XNL4Y+kCUVnBZrNu/q3bGB1uIC8tL2t0sKx4OPcNCe8EhVQjwKRECgYEA4uothdhKRPtwDIsVsHfN74Yjr7SMVay7gIcaPrjqyGnzYnS+oJWOx50AaFNK6Rko5JAF3jF9NxE0B4yfMPAic6Y88hpEkpcJ4HMPn2Y1WdbFCu/WYgVUJICCys6VNLCcXj85umtyIY38Y9VbEMW/SV49GZBeFQqy4FoP/fvBrkECgYEAnfjTDYwgdmJdsUqyNzAocwcJXG2rVtYc7Txrl0TltcwuJmgoSywdzyOP2R9+NZsfoxWDzG0/yr15ApMvUcnnTwHN/8bGQ9SLatFLKqS4EtdwDKKS1JvNbs7V1myQGpt7jbShZOI0e6Fs4xP8ujxsLeGgiq9mZrS9UdRj5XKDoVM=
cool.api.rsa.public.key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0erPAWesjkp9J4htmfCyqKS9npmT9dW3KqWTfb4c7x/QBUtKuokWOO0XikHd4bGUa9kl+twSv/5A3kYz1B9eg6wRuDJoads+G5U7rVQjzdoUtLaf3lNXkuSehl4uHUPQfNa6vcmvzraXPxJjEpYzj9WZh7uJqq2oSgw42H1qdbFCXSaE5BwsOb+2vZXjzh4RO10Sy3Qb1UqGsoZoxVzrtDeEctCjrecFyQr96L2UtYa4NTxSTfu4rgObrwIOMvqqnLsXEzK/rd6kIHYjkZYQCOa48AedWp2YKQ7Ldclj+VMLnXvl42J9exVkbs++8k3P5sI9fdZX4Ey2RBjnSoAo/QIDAQAB
wallet.api.rsa.public.key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvU5WUX5MaZhS4MRfZ5OeqmSxTgjNi64SEwTiDYS++DRHRFTEguk1g5AbiW3l9eEdATeVk0WX+T6ZIIa2do3bQOKhlMtRwWMWQIucjGa7ySOCuicvnCD2HAQ2EThfqQdSpAW5UpcyodrhcyUkuevBA4fQQ06k9lB4FjqWtao2+aYFIPFPu8Wu28KI/9QIMLI02Q1YY3duJ67QW4EM4I2oS0t3sWJeZtIJPRHFWW1EaLJz2FdbJJq+z6D2p++9pmkHsvdnktUUO+nPL3PCLtxGYxEwr/AqTYR/1yXfkVWe3nHXc+qvRt967X1hDHC+gEPJItr7kUk3pQTGBv9kNu75DwIDAQAB
wallet.api.rsa.public.key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvU5WUX5MaZhS4MRfZ5OeqmSxTgjNi64SEwTiDYS++DRHRFTEguk1g5AbiW3l9eEdATeVk0WX+T6ZIIa2do3bQOKhlMtRwWMWQIucjGa7ySOCuicvnCD2HAQ2EThfqQdSpAW5UpcyodrhcyUkuevBA4fQQ06k9lB4FjqWtao2+aYFIPFPu8Wu28KI/9QIMLI02Q1YY3duJ67QW4EM4I2oS0t3sWJeZtIJPRHFWW1EaLJz2FdbJJq+z6D2p++9pmkHsvdnktUUO+nPL3PCLtxGYxEwr/AqTYR/1yXfkVWe3nHXc+qvRt967X1hDHC+gEPJItr7kUk3pQTGBv9kNu75DwIDAQAB
store.open.url=https://zhengxin.zhidiansoft.com:5943
store.open.appId=289704779317445
store.open.appKey=IGSAEQoakR2HEaYx
store.open.secret=aPsA99K1obFeFm3m