Merge branch 'master' into prod

# Conflicts:
#	cash-api/product-server/src/main/java/com/czg/controller/user/UProductController.java
#	cash-service/product-service/src/main/java/com/czg/service/product/service/impl/UProductServiceImpl.java
This commit is contained in:
2025-04-21 09:32:09 +08:00
152 changed files with 4846 additions and 527 deletions

View File

@@ -74,7 +74,7 @@ public class AuthorizationController {
@GetMapping("/permission")
public CzgResult<?> getPermission() {
return CzgResult.success();
return CzgResult.success(StpKit.USER.getPermissionList());
}
@Resource
@@ -90,7 +90,13 @@ public class AuthorizationController {
// rabbitPublisher.sendOrderPrintMsg("552");
// printMqListener.orderPrint("1");
// return CzgResult.success(Map.of("token", StpKit.USER.getShopId()));
return CzgResult.success(shopInfoService.getById(1));
return CzgResult.success(StpKit.USER.getLoginId());
}
@GetMapping("test1")
public CzgResult<?> login1() throws IOException {
authorizationService.switchTo(86L);
return CzgResult.success(StpKit.USER.getLoginId());
}
/**

View File

@@ -0,0 +1,106 @@
package com.czg.controller.admin;
import com.czg.account.dto.ShopBranchDTO;
import com.czg.account.entity.ShopConfig;
import com.czg.account.enums.BranchDataSyncMethodEnum;
import com.czg.account.param.ShopBranchParam;
import com.czg.account.service.ShopBranchService;
import com.czg.account.service.ShopConfigService;
import com.czg.log.annotation.OperationLog;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
/**
* 分店管理
*
* @author tankaikai
* @since 2025-04-07 14:05
*/
@RestController
@RequestMapping("/admin/shop/branch")
public class ShopBranchController {
@Resource
private ShopBranchService shopBranchService;
@Resource
private ShopConfigService shopConfigService;
/**
* 分店列表
*/
@GetMapping("page")
@OperationLog("分店管理-分页")
public CzgResult<Page<ShopBranchDTO>> getBranchPage(ShopBranchParam param) {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
Page<ShopBranchDTO> data = shopBranchService.findPage(param);
return CzgResult.success(data);
}
/**
* 设置数据同步方式
*
* @param dataSyncMethod 数据同步方式 auto-实时自动同步 manual-手动同步
*/
@PostMapping("/setting/dataSyncMethod")
@OperationLog("分店管理-设置数据同步方式")
public CzgResult<Void> settingDataSyncMethod(@RequestParam String dataSyncMethod) {
Long shopId = StpKit.USER.getShopId(0L);
shopBranchService.settingDataSyncMethod(shopId, dataSyncMethod);
return CzgResult.success();
}
/**
* 同步启用
*
* @param branchShopId 分店id
*/
@PostMapping("/data/sync/enable")
@OperationLog("分店管理-同步启用")
public CzgResult<Void> dataSyncEnable(@RequestParam Long branchShopId) {
shopBranchService.dataSyncEnable(branchShopId);
CzgResult<Void> ret = CzgResult.success();
ret.setMsg("启用成功,数据正在后台同步中...");
return ret;
}
/**
* 账号启用
*
* @param branchShopId 分店id
*/
@PostMapping("/account/enable")
@OperationLog("分店管理-账号启用")
public CzgResult<Void> accountEnable(@RequestParam Long branchShopId) {
shopBranchService.accountEnable(branchShopId);
return CzgResult.success();
}
/**
* 账号禁用
*
* @param branchShopId 分店id
*/
@PostMapping("/account/disable")
@OperationLog("分店管理-账号禁用")
public CzgResult<Void> accountDisable(@RequestParam Long branchShopId) {
shopBranchService.accountDisable(branchShopId);
return CzgResult.success();
}
/**
* 获取数据同步方式
* @return 数据同步方式 auto-实时自动同步 manual-手动同步
*/
@GetMapping("/get/dataSyncMethod")
@OperationLog("分店管理-获取数据同步方式")
public CzgResult<String> getDataSyncMethod() {
Long shopId = StpKit.USER.getShopId(0L);
ShopConfig shopConfig = shopConfigService.getById(shopId);
return CzgResult.success(shopConfig == null? BranchDataSyncMethodEnum.AUTO.getValue() : shopConfig.getBranchDataSyncMethod());
}
}

View File

@@ -1,10 +1,14 @@
package com.czg.controller.admin;
import cn.dev33.satoken.session.TokenSign;
import cn.hutool.core.collection.CollUtil;
import com.czg.account.dto.PageDTO;
import com.czg.account.dto.shopinfo.ShopBranchSelectDTO;
import com.czg.account.dto.shopinfo.ShopDetailDTO;
import com.czg.account.dto.shopinfo.ShopInfoAddDTO;
import com.czg.account.dto.shopinfo.ShopInfoEditDTO;
import com.czg.account.entity.ShopInfo;
import com.czg.account.service.AuthorizationService;
import com.czg.account.service.ShopInfoService;
import com.czg.annotation.SaAdminCheckPermission;
import com.czg.annotation.SaAdminCheckRole;
@@ -12,17 +16,23 @@ import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 店铺管理
*
* @author Administrator
*/
@RestController
@RequestMapping("/admin/shopInfo")
public class ShopInfoController {
private final ShopInfoService shopInfoService;
@Resource
private AuthorizationService authorizationService;
public ShopInfoController(ShopInfoService shopInfoService) {
this.shopInfoService = shopInfoService;
@@ -35,8 +45,8 @@ public class ShopInfoController {
@SaAdminCheckRole("管理员")
@SaAdminCheckPermission(value = "shopInfo:list", name = "店铺列表")
@GetMapping
public CzgResult<Page<ShopInfo>> get(PageDTO pageDTO, String shopName, Integer status) {
return CzgResult.success(shopInfoService.get(pageDTO, shopName, status));
public CzgResult<Page<ShopInfo>> get(PageDTO pageDTO, String shopName, Integer status, Integer isHeadShop) {
return CzgResult.success(shopInfoService.get(pageDTO, shopName, status, isHeadShop));
}
/**
@@ -83,4 +93,37 @@ public class ShopInfoController {
public CzgResult<?> delete(@RequestParam Integer id) {
return CzgResult.success(shopInfoService.remove(new QueryWrapper().eq(ShopInfo::getId, id)));
}
/**
* 店铺分店列表(下拉展示主店和分店使用,默认第一个是主店,其余是分店)
*/
@GetMapping("branchList")
public CzgResult<List<ShopBranchSelectDTO>> findShopBranch() {
Long shopId = StpKit.USER.getShopId(0L);
String tokenValue = StpKit.USER.getTokenInfo().getTokenValue();
Long headId = StpKit.USER.getHeadId();
List<TokenSign> tokenSignList = StpKit.USER.getSession().getTokenSignList();
if (headId != null && CollUtil.isEmpty(tokenSignList)) {
shopId = StpKit.USER.getHeadShopId();
} else {
long count = tokenSignList.stream().filter(obj -> tokenValue.equals(obj.getValue())).count();
if (headId != null && count == 0) {
shopId = StpKit.USER.getHeadShopId();
}
}
List<ShopBranchSelectDTO> data = shopInfoService.findShopBranch(shopId);
return CzgResult.success(data);
}
/**
* 切换店铺
*
* @param shopId 店铺ID
*/
@PostMapping("/change/{shopId}")
public CzgResult<Void> change(@PathVariable Long shopId) {
authorizationService.switchTo(shopId);
return CzgResult.success();
}
}

View File

@@ -1,9 +1,7 @@
package com.czg.controller.admin;
import cn.hutool.core.util.StrUtil;
import com.czg.account.dto.shopuser.*;
import com.czg.account.entity.ShopUser;
import com.czg.account.entity.ShopUserFlow;
import com.czg.account.service.ShopUserFlowService;
import com.czg.account.service.ShopUserService;
import com.czg.account.vo.ShopUserFlowVO;
@@ -12,9 +10,7 @@ import com.czg.annotation.SaStaffCheckPermission;
import com.czg.enums.ShopUserFlowBizEnum;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.validation.annotation.Validated;
@@ -47,7 +43,7 @@ public class ShopUserController {
@GetMapping("/summary")
@SaStaffCheckPermission("yun_xu_guan_li_hui_yuan_xin_xi")
public CzgResult<ShopUserSummaryDTO> summary(Integer isVip) {
return CzgResult.success(shopUserService.getSummary(StpKit.USER.getShopId(), isVip));
return CzgResult.success(shopUserService.getSummary(StpKit.USER.getUsableShopId(), isVip));
}
/**
@@ -71,7 +67,7 @@ public class ShopUserController {
@GetMapping("/flow")
@SaStaffCheckPermission("yun_xu_guan_li_hui_yuan_xin_xi")
public CzgResult<Page<ShopUserFlowVO>> flow(Integer userId, String bizCode, String startTime, String endTime) {
return CzgResult.success(shopUserFlowService.pageInfo(StpKit.USER.getShopId(), userId, bizCode, startTime, endTime));
return CzgResult.success(shopUserFlowService.pageInfo(StpKit.USER.getUsableShopId(), userId, bizCode, startTime, endTime));
}
/**
@@ -87,7 +83,7 @@ public class ShopUserController {
@GetMapping("/flow/download")
@SaStaffCheckPermission("yun_xu_guan_li_hui_yuan_xin_xi")
public void flowDownload(Integer userId, String bizCode, String startTime, String endTime, HttpServletResponse response) throws IOException {
shopUserFlowService.flowDownload(StpKit.USER.getShopId(), userId, bizCode, startTime, endTime, response);
shopUserFlowService.flowDownload(StpKit.USER.getUsableShopId(), userId, bizCode, startTime, endTime, response);
}
/**
@@ -129,7 +125,7 @@ public class ShopUserController {
@SaAdminCheckPermission(value = "shopUser:add", name = "店铺用户添加")
@PostMapping
public CzgResult<Boolean> add(@RequestBody @Validated ShopUserAddDTO shopUserAddDTO) {
return CzgResult.success(shopUserService.add(StpKit.USER.getShopId(), shopUserAddDTO));
return CzgResult.success(shopUserService.add(StpKit.USER.getUsableShopId(), shopUserAddDTO));
}
/**
@@ -141,7 +137,7 @@ public class ShopUserController {
@SaAdminCheckPermission(value = "shopUser:edit", name = "店铺用户修改")
@PutMapping
public CzgResult<Boolean> edit(@RequestBody @Validated ShopUserEditDTO shopUserEditDTO) {
return CzgResult.success(shopUserService.updateInfo(StpKit.USER.getShopId(), shopUserEditDTO));
return CzgResult.success(shopUserService.updateInfo(StpKit.USER.getUsableShopId(), shopUserEditDTO));
}
/**
@@ -154,7 +150,7 @@ public class ShopUserController {
@PutMapping("/money")
public CzgResult<Boolean> editMoney(@RequestBody @Validated ShopUserMoneyEditDTO shopUserMoneyEditDTO) {
shopUserMoneyEditDTO.setBizEnum(ShopUserFlowBizEnum.ADMIN_IN);
return CzgResult.success(shopUserService.updateMoney(StpKit.USER.getShopId(), shopUserMoneyEditDTO) > 0L);
return CzgResult.success(shopUserService.updateMoney(StpKit.USER.getUsableShopId(), shopUserMoneyEditDTO) > 0L);
}
}

View File

@@ -0,0 +1,92 @@
package com.czg.controller.admin;
import com.czg.account.entity.SyncNotice;
import com.czg.account.service.SyncNoticeService;
import com.czg.product.dto.SyncNoticeReadDTO;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 通知中心-同步消息
* @author Administrator
*/
@RestController
@RequestMapping("/admin/syncNotice")
public class SyncNoticeController {
@Resource
private SyncNoticeService syncNoticeService;
/**
* 通知消息列表
* @param name 名称
* @param startTime 起始时间
* @param endTime 结束时间
* @param title 数据同步/数据变动/库存预警
* @param isRead 0-未读 1-已读
* @return 分页数据
*/
@GetMapping
public CzgResult<Page<SyncNotice>> page(@RequestParam(required = false) String name, @RequestParam(required = false) String startTime,
@RequestParam(required = false) String endTime, @RequestParam(required = false) String title,
@RequestParam(required = false) Integer isRead) {
return CzgResult.success(syncNoticeService.pageInfo(StpKit.USER.getShopId(), name, startTime, endTime, title, isRead));
}
/**
* 详情
* @param id id
* @return 详细信息
*/
@GetMapping("/detail")
public CzgResult<SyncNotice> detail(@RequestParam Long id) {
return CzgResult.success(syncNoticeService.getOne(new QueryWrapper().eq(SyncNotice::getShopId, StpKit.USER.getShopId()).eq(SyncNotice::getId, id)));
}
/**
* 已读消息, 不传递已读所有
* @return 是否成功
*/
@PutMapping("/read")
public CzgResult<Boolean> read(@RequestBody @Validated SyncNoticeReadDTO syncNoticeReadDTO) {
return CzgResult.success(syncNoticeService.read(StpKit.USER.getShopId(), syncNoticeReadDTO));
}
/**
* 清空已读
* @return 是否成功
*/
@DeleteMapping("/clear")
public CzgResult<Boolean> clear() {
return CzgResult.success(syncNoticeService.remove(new QueryWrapper().eq(SyncNotice::getShopId, StpKit.USER.getShopId()).eq(SyncNotice::getIsRead, 1)));
}
/**
* 删除
* @param id id
* @return 是否成功
*/
@DeleteMapping
public CzgResult<Boolean> delete(@RequestParam Long id) {
return CzgResult.success(syncNoticeService.remove(new QueryWrapper().eq(SyncNotice::getShopId, StpKit.USER.getShopId()).eq(SyncNotice::getId, id)));
}
/**
* 消息统计
* @return 消息记录数
*/
@GetMapping("/count")
public CzgResult<Long> count(@RequestParam(required = false) Integer isRead) {
QueryWrapper queryWrapper = new QueryWrapper().eq(SyncNotice::getShopId, StpKit.USER.getShopId());
queryWrapper.eq(SyncNotice::getIsRead, isRead);
return CzgResult.success(syncNoticeService.count(queryWrapper));
}
}

View File

@@ -4,7 +4,6 @@ import com.czg.account.dto.shopuser.ShopUserAddDTO;
import com.czg.account.dto.shopuser.ShopUserDetailDTO;
import com.czg.account.dto.shopuser.ShopUserVipCardDTO;
import com.czg.account.entity.MemberPointsLog;
import com.czg.account.entity.PointsExchangeRecord;
import com.czg.account.entity.ShopUser;
import com.czg.account.entity.ShopUserFlow;
import com.czg.account.service.MemberPointsLogService;
@@ -18,14 +17,9 @@ import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashSet;
import java.util.Objects;
/**
* 店铺会员相关
*
@@ -51,7 +45,7 @@ public class UShopUserController {
*/
@GetMapping
public CzgResult<ShopUserDetailDTO> get(Long shopId) {
return CzgResult.success(shopUserService.getInfo(shopId == null ? StpKit.USER.getShopId() : shopId, StpKit.USER.getLoginIdAsLong()));
return CzgResult.success(shopUserService.getInfo(shopId == null ? StpKit.USER.getUsableShopId() : shopId, StpKit.USER.getLoginIdAsLong()));
}
/**
@@ -71,7 +65,7 @@ public class UShopUserController {
*/
@GetMapping("/code")
public CzgResult<String> code(Long shopId) {
return shopUserService.getCode(StpKit.USER.getLoginIdAsLong(), shopId == null ? StpKit.USER.getShopId() : shopId);
return shopUserService.getCode(StpKit.USER.getLoginIdAsLong(), shopId == null ? StpKit.USER.getUsableShopId() : shopId);
}
/**
@@ -82,7 +76,7 @@ public class UShopUserController {
@PostMapping
@Debounce("#shopUserAddDTO.phone")
public CzgResult<Boolean> join(@RequestBody @Validated ShopUserAddDTO shopUserAddDTO) {
return CzgResult.success(shopUserService.join(StpKit.USER.getShopId(), StpKit.USER.getLoginIdAsLong(), shopUserAddDTO));
return CzgResult.success(shopUserService.join(StpKit.USER.getUsableShopId(), StpKit.USER.getLoginIdAsLong(), shopUserAddDTO));
}

View File

@@ -1,15 +1,11 @@
package com.czg.controller.user;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.czg.account.dto.user.userinfo.UserInfoDTO;
import com.czg.account.dto.user.userinfo.UserInfoEditDTO;
import com.czg.account.dto.user.userinfo.UserInfoPwdEditDTO;
import com.czg.account.entity.UserInfo;
import com.czg.account.service.UserInfoService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
@@ -38,7 +34,7 @@ public class UserController {
*/
@PutMapping
public CzgResult<Boolean> update(@RequestBody UserInfoEditDTO userInfoEditDTO) {
return CzgResult.success(userInfoService.updateInfo(StpKit.USER.getShopId(-1L), StpKit.USER.getLoginIdAsLong(), userInfoEditDTO));
return CzgResult.success(userInfoService.updateInfo(StpKit.USER.getUsableShopId(), StpKit.USER.getLoginIdAsLong(), userInfoEditDTO));
}
/**

View File

@@ -1,5 +1,7 @@
package com.czg.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.CzgPayUtils;
import com.czg.entity.CzgBaseRespParams;
@@ -9,10 +11,9 @@ import com.czg.task.StatisticTask;
import com.czg.utils.AssertUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
/**
* @author ww
@@ -32,7 +33,7 @@ public class NotifyController {
@RequestMapping("/payCallBack")
public String notifyCallBack(@RequestBody CzgBaseRespParams respParams){
public String notifyCallBack(@RequestBody CzgBaseRespParams respParams) {
JSONObject czg = CzgPayUtils.getCzg(respParams);
AssertUtil.isNull(czg, "支付回调数据为空");
log.info("支付回调数据为:{}", czg);
@@ -41,7 +42,7 @@ public class NotifyController {
}
@RequestMapping("/refundCallBack")
public String refundCallBack(@RequestBody CzgBaseRespParams respParams){
public String refundCallBack(@RequestBody CzgBaseRespParams respParams) {
JSONObject czg = CzgPayUtils.getCzg(respParams);
AssertUtil.isNull(czg, "退款回调数据为空");
log.info("退款回调数据为:{}", czg);
@@ -51,8 +52,18 @@ public class NotifyController {
@Resource
private PrintMqListener printMqListener;
@RequestMapping("/test")
public void test(@RequestParam String id) {
printMqListener.orderPrint(id);
}
@GetMapping("/anew/statistic/history/data")
public String statistic(@RequestParam String now) {
String format = DateUtil.format(new Date(), "yyyyMMddHHmm");
if (format.equals(now)) {
ThreadUtil.execAsync(() -> statisticTask.statisticHistoryData());
}
return SUCCESS;
}
}

View File

@@ -44,8 +44,10 @@ public class DataSummaryController {
public CzgResult<ShopOrderStatistic> getTradeData(DataSummaryTradeParam param) {
ValidatorUtil.validateEntity(param, DefaultGroup.class);
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
ShopOrderStatistic data = dataSummaryService.getTradeData(param);
if (param.getShopId() == null) {
param.setShopId(shopId);
}
ShopOrderStatistic data = dataSummaryService.getArchiveTradeData(param);
return CzgResult.success(data);
}
@@ -59,7 +61,9 @@ public class DataSummaryController {
public CzgResult<Page<DataSummaryProductSaleRankingVo>> getProductSaleData(DataSummaryProductSaleParam param) {
ValidatorUtil.validateEntity(param, DefaultGroup.class);
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
if (param.getShopId() == null) {
param.setShopId(shopId);
}
Page<DataSummaryProductSaleRankingVo> data = dataSummaryService.getProductSaleRankingPage(param);
return CzgResult.success(data);
}
@@ -67,15 +71,18 @@ public class DataSummaryController {
/**
* 销售趋势柱状图 左下
*
* @param day 天数
* @param day 天数
* @param shopId 店铺id
*/
@GetMapping("dateAmount")
@OperationLog("销售趋势柱状图 左下")
@SaStaffCheckPermission("yun_xu_cha_kan_jing_ying_shu_ju")
//@SaAdminCheckPermission("dataSummary:dateAmount")
public CzgResult<DataSummaryDateAmountVo> getDateAmount(@RequestParam Integer day) {
public CzgResult<DataSummaryDateAmountVo> getDateAmount(@RequestParam Integer day, @RequestParam(required = false) Long shopId) {
AssertUtil.isNull(day, "天数不能为空");
Long shopId = StpKit.USER.getShopId(0L);
if (shopId == null) {
shopId = StpKit.USER.getShopId(0L);
}
DataSummaryDateAmountVo data = dataSummaryService.getSummaryAmountData(shopId, day);
return CzgResult.success(data);
}
@@ -84,13 +91,16 @@ public class DataSummaryController {
* 支付占比饼图 左下
*
* @param day 天数
* @param shopId 店铺id
*/
@GetMapping("datePayType")
@OperationLog("支付占比饼图 左下")
@SaStaffCheckPermission("yun_xu_cha_kan_jing_ying_shu_ju")
//@SaAdminCheckPermission("dataSummary:datePayType")
public CzgResult<DataSummaryPayTypeVo> shopSummaryPayType(@RequestParam Integer day) {
Long shopId = StpKit.USER.getShopId(0L);
public CzgResult<DataSummaryPayTypeVo> shopSummaryPayType(@RequestParam Integer day, @RequestParam(required = false) Long shopId) {
if (shopId == null) {
shopId = StpKit.USER.getShopId(0L);
}
DataSummaryPayTypeVo data = dataSummaryService.getSummaryPayTypeData(shopId, day);
return CzgResult.success(data);
}

View File

@@ -38,7 +38,9 @@ public class SaleSummaryController {
//@SaAdminCheckPermission("saleSummary:count")
public CzgResult<SaleSummaryCountVo> summaryCount(SaleSummaryCountParam param) {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
if (param.getShopId() == null) {
param.setShopId(shopId);
}
SaleSummaryCountVo data = saleSummaryService.summaryCount(param);
return CzgResult.success(data);
}
@@ -51,7 +53,9 @@ public class SaleSummaryController {
//@SaAdminCheckPermission("saleSummary:page")
public CzgResult<Page<SaleSummaryInfoVo>> summaryPage(SaleSummaryCountParam param) {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
if (param.getShopId() == null) {
param.setShopId(shopId);
}
Page<SaleSummaryInfoVo> page = saleSummaryService.summaryPage(param);
return CzgResult.success(page);
}
@@ -65,7 +69,9 @@ public class SaleSummaryController {
//@SaAdminCheckPermission("saleSummary:export")
public List<SaleSummaryInfoVo> summaryExport(SaleSummaryCountParam param) {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
if (param.getShopId() == null) {
param.setShopId(shopId);
}
return saleSummaryService.summaryList(param);
}

View File

@@ -37,7 +37,9 @@ public class TableSummaryController {
//@SaAdminCheckPermission("tableSummary:list")
public CzgResult<List<TableSummaryInfoVo>> summaryList(TableSummaryParam param) {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
if (param.getShopId() == null) {
param.setShopId(shopId);
}
List<TableSummaryInfoVo> data = tableSummaryService.summaryList(param);
return CzgResult.success(data);
}
@@ -51,7 +53,9 @@ public class TableSummaryController {
//@SaAdminCheckPermission("tableSummary:export")
public List<TableSummaryExportVo> summaryExport(TableSummaryParam param) {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
if (param.getShopId() == null) {
param.setShopId(shopId);
}
return tableSummaryService.summaryExportList(param);
}

View File

@@ -1,13 +1,27 @@
package com.czg.task;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.czg.order.entity.ShopOrderStatistic;
import com.czg.order.entity.ShopProdStatistic;
import com.czg.order.entity.ShopTableOrderStatistic;
import com.czg.order.service.ShopOrderStatisticService;
import com.czg.order.service.ShopProdStatisticService;
import com.czg.order.service.ShopTableOrderStatisticService;
import com.czg.service.order.mapper.ShopOrderStatisticMapper;
import com.czg.service.order.mapper.ShopProdStatisticMapper;
import com.czg.service.order.mapper.ShopTableOrderStatisticMapper;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.DbChain;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.util.List;
/**
* @author Administrator
*/
@@ -20,15 +34,81 @@ public class StatisticTask {
private ShopProdStatisticService shopProdStatisticService;
@Resource
private ShopOrderStatisticService shopOrderStatisticService;
@Resource
private ShopOrderStatisticMapper shopOrderStatisticMapper;
@Resource
private ShopProdStatisticMapper shopProdStatisticMapper;
@Resource
private ShopTableOrderStatisticMapper shopTableOrderStatisticMapper;
// @Scheduled(cron = "1/6 * * * * ? ")
/**
* 基础统计
*
* @param dateTime 日期时间
*/
private void baseStatistic(DateTime dateTime) {
try {
shopOrderStatisticService.statistic(dateTime);
} catch (Exception e) {
log.error("统计订单数据失败", e);
}
try {
shopProdStatisticService.statistic(dateTime);
} catch (Exception e) {
log.error("统计商品数据失败", e);
}
try {
shopTableOrderStatisticService.statistic(dateTime);
} catch (Exception e) {
log.error("统计桌台数据失败", e);
}
}
// @Scheduled(cron = "1/6 * * * * ? ")
@Scheduled(cron = "0 0 8 * * ?")
public void run() {
long start = System.currentTimeMillis();
log.info("定时任务执行,开始统计数据");
shopOrderStatisticService.statistic();
shopProdStatisticService.statistic();
shopTableOrderStatisticService.statistic();
// 获取前一天
DateTime yesterday = DateUtil.yesterday();
baseStatistic(yesterday);
log.info("定时任务执行完毕,耗时:{}ms", start - System.currentTimeMillis());
}
@Scheduled(cron = "0 0,15,30,45 * * * ? ")
public void run2() {
long start = System.currentTimeMillis();
log.info("定时任务2执行开始统计数据");
// 获取当天
DateTime today = DateUtil.date();
baseStatistic(today);
log.info("定时任务2执行完毕耗时:{}ms", start - System.currentTimeMillis());
}
/**
* 统计历史数据
*/
public void statisticHistoryData() {
// 指定开始日期
LocalDate startDate = LocalDate.of(2024, 3, 1);
// 指定结束日期
LocalDate endDate = LocalDate.now();
List<Long> shopIdList = DbChain.table("tb_shop_info").select("id").objListAs(Long.class);
List<List<Long>> split = CollUtil.split(shopIdList, 10);
// 1.清除历史统计的数据
for (List<Long> splitIdList : split) {
splitIdList.parallelStream().forEach(shopId -> {
shopOrderStatisticMapper.deleteByQuery(QueryWrapper.create().eq(ShopOrderStatistic::getShopId, shopId));
shopProdStatisticMapper.deleteByQuery(QueryWrapper.create().eq(ShopProdStatistic::getShopId, shopId));
shopTableOrderStatisticMapper.deleteByQuery(QueryWrapper.create().eq(ShopTableOrderStatistic::getShopId, shopId));
});
}
// 2.开始从2024-3-1开始统计数据
startDate.datesUntil(endDate.plusDays(1)).forEach(date -> {
System.out.println(date.toString());
DateTime dateTime = DateUtil.parseDate(date.toString());
System.out.println(dateTime);
baseStatistic(dateTime);
});
}
}

View File

@@ -1,14 +1,18 @@
package com.czg.controller.admin;
import cn.hutool.core.thread.ThreadUtil;
import com.czg.log.annotation.OperationLog;
import com.czg.product.dto.ConsGroupDTO;
import com.czg.product.service.ConsGroupService;
import com.czg.product.service.ShopSyncService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.utils.AssertUtil;
import com.czg.validator.group.DefaultGroup;
import com.czg.validator.group.InsertGroup;
import com.czg.validator.group.UpdateGroup;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -27,6 +31,8 @@ import java.util.List;
@RequestMapping("/admin/product/consGroup")
public class ConsGroupController {
private final ConsGroupService consGroupService;
@Resource
private ShopSyncService shopSyncService;
/**
* 分页
@@ -72,6 +78,7 @@ public class ConsGroupController {
//@SaAdminCheckPermission("consGroup:add")
public CzgResult<Void> addConsGroup(@RequestBody @Validated({InsertGroup.class, DefaultGroup.class}) ConsGroupDTO dto) {
consGroupService.addConsGroup(dto);
asyncToBranchShop(dto.getId());
return CzgResult.success();
}
@@ -83,6 +90,7 @@ public class ConsGroupController {
//@SaAdminCheckPermission("consGroup:update")
public CzgResult<Void> updateConsGroup(@RequestBody @Validated({UpdateGroup.class, DefaultGroup.class}) ConsGroupDTO dto) {
consGroupService.updateConsGroup(dto);
asyncToBranchShop(dto.getId());
return CzgResult.success();
}
@@ -98,6 +106,7 @@ public class ConsGroupController {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
consGroupService.disableConsGroup(id);
asyncToBranchShop(id);
return CzgResult.success();
}
@@ -113,6 +122,15 @@ public class ConsGroupController {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
consGroupService.enableConsGroup(id);
asyncToBranchShop(id);
return CzgResult.success();
}
private void asyncToBranchShop(Long id) {
long shopId = StpKit.USER.getShopId(0L);
long sysUserId = StpKit.USER.getLoginIdAsLong();
ThreadUtil.execAsync(() -> {
shopSyncService.syncConsGroupBySourceShop(shopId, id, sysUserId);
});
}
}

View File

@@ -1,12 +1,13 @@
package com.czg.controller.admin;
import cn.hutool.core.thread.ThreadUtil;
import com.czg.enums.CrudEnum;
import com.czg.log.annotation.OperationLog;
import com.czg.product.dto.ConsInfoDTO;
import com.czg.product.param.ConsInfoParam;
import com.czg.product.param.ConsReportDamageParam;
import com.czg.product.param.ConsSubUnitParam;
import com.czg.product.service.ConsInfoService;
import com.czg.product.service.ShopSyncService;
import com.czg.product.vo.ConsStatisticsVo;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
@@ -16,6 +17,7 @@ import com.czg.validator.group.DefaultGroup;
import com.czg.validator.group.InsertGroup;
import com.czg.validator.group.UpdateGroup;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -34,6 +36,8 @@ import java.util.List;
@RequestMapping("/admin/product/cons")
public class ConsInfoController {
private final ConsInfoService consInfoService;
@Resource
private ShopSyncService shopSyncService;
/**
* 分页
@@ -79,6 +83,7 @@ public class ConsInfoController {
//@SaAdminCheckPermission("consInfo:add")
public CzgResult<Void> addConsInfo(@RequestBody @Validated({InsertGroup.class, DefaultGroup.class}) ConsInfoDTO dto) {
consInfoService.addConsInfo(dto);
asyncToBranchShop(dto.getId());
return CzgResult.success();
}
@@ -90,6 +95,7 @@ public class ConsInfoController {
//@SaAdminCheckPermission("consInfo:update")
public CzgResult<Void> updateConsInfo(@RequestBody @Validated({UpdateGroup.class, DefaultGroup.class}) ConsInfoDTO dto) {
consInfoService.updateConsInfo(dto);
asyncToBranchShop(dto.getId());
return CzgResult.success();
}
@@ -120,6 +126,7 @@ public class ConsInfoController {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
consInfoService.disableConsInfo(id);
asyncToBranchShop(id);
return CzgResult.success();
}
@@ -135,6 +142,7 @@ public class ConsInfoController {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
consInfoService.enableConsInfo(id);
asyncToBranchShop(id);
return CzgResult.success();
}
@@ -167,6 +175,7 @@ public class ConsInfoController {
ValidatorUtil.validateEntity(param, InsertGroup.class);
}
consInfoService.modifySubUnit(param);
asyncToBranchShop(param.getId());
return CzgResult.success();
}
@@ -183,4 +192,12 @@ public class ConsInfoController {
return CzgResult.success(data);
}
private void asyncToBranchShop(Long id) {
long shopId = StpKit.USER.getShopId(0L);
long sysUserId = StpKit.USER.getLoginIdAsLong();
ThreadUtil.execAsync(() -> {
shopSyncService.syncConsInfoBySourceShop(shopId, id, sysUserId);
});
}
}

View File

@@ -17,6 +17,8 @@ import com.mybatisflex.core.paginate.Page;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 耗材进销存
@@ -90,9 +92,11 @@ public class ConsStockFlowController {
@PostMapping("reportDamage")
@OperationLog("耗材报损")
//@SaAdminCheckPermission("consStockFlow:reportDamage")
public CzgResult<Void> reportDamage(@RequestBody ConsReportDamageParam param) {
ValidatorUtil.validateEntity(param, DefaultGroup.class);
consStockFlowService.reportDamage(param);
public CzgResult<Void> reportDamage(@RequestBody List<ConsReportDamageParam> params) {
params.forEach(item -> {
ValidatorUtil.validateEntity(item, DefaultGroup.class);
consStockFlowService.reportDamage(item);
});
return CzgResult.success();
}

View File

@@ -6,6 +6,7 @@ import com.czg.config.RabbitPublisher;
import com.czg.log.annotation.OperationLog;
import com.czg.product.dto.ProdGroupDTO;
import com.czg.product.service.ProdGroupService;
import com.czg.product.service.ShopSyncService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.utils.AssertUtil;
@@ -13,6 +14,7 @@ import com.czg.validator.group.DefaultGroup;
import com.czg.validator.group.InsertGroup;
import com.czg.validator.group.UpdateGroup;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -32,6 +34,8 @@ import java.util.List;
public class ProdGroupController {
private final ProdGroupService prodGroupService;
private final RabbitPublisher rabbitPublisher;
@Resource
private ShopSyncService shopSyncService;
/**
* 分页
@@ -79,6 +83,7 @@ public class ProdGroupController {
Long shopId = StpKit.USER.getShopId(0L);
dto.setShopId(shopId);
prodGroupService.addProdGroup(dto);
asyncToBranchShop(dto.getId());
ThreadUtil.execAsync(() -> {
rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId));
});
@@ -95,6 +100,7 @@ public class ProdGroupController {
Long shopId = StpKit.USER.getShopId(0L);
dto.setShopId(shopId);
prodGroupService.updateProdGroup(dto,true);
asyncToBranchShop(dto.getId());
ThreadUtil.execAsync(() -> {
rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId));
});
@@ -111,6 +117,7 @@ public class ProdGroupController {
Long shopId = StpKit.USER.getShopId(0L);
dto.setShopId(shopId);
prodGroupService.updateProdGroup(dto,false);
asyncToBranchShop(dto.getId());
ThreadUtil.execAsync(() -> {
rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId));
});
@@ -145,6 +152,7 @@ public class ProdGroupController {
AssertUtil.isNull(id, "{}不能为空", "id");
Long shopId = StpKit.USER.getShopId(0L);
prodGroupService.disableProdGroup(shopId, id);
asyncToBranchShop(id);
ThreadUtil.execAsync(() -> {
rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId));
});
@@ -162,9 +170,18 @@ public class ProdGroupController {
AssertUtil.isNull(id, "{}不能为空", "id");
Long shopId = StpKit.USER.getShopId(0L);
prodGroupService.enableProdGroup(shopId, id);
asyncToBranchShop(id);
ThreadUtil.execAsync(() -> {
rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId));
});
return CzgResult.success();
}
private void asyncToBranchShop(Long id) {
long shopId = StpKit.USER.getShopId(0L);
long sysUserId = StpKit.USER.getLoginIdAsLong();
ThreadUtil.execAsync(() -> {
shopSyncService.syncGroupBySourceShop(shopId, id, sysUserId);
});
}
}

View File

@@ -2,8 +2,6 @@ package com.czg.controller.admin;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.annotation.SaStaffCheckPermission;
import com.czg.config.RabbitPublisher;
import com.czg.exception.CzgException;
@@ -15,6 +13,8 @@ import com.czg.product.entity.ProductStockFlow;
import com.czg.product.param.*;
import com.czg.product.service.ProdConsRelationService;
import com.czg.product.service.ProductService;
import com.czg.product.service.ShopSyncService;
import com.czg.product.service.UProductService;
import com.czg.product.vo.ProductStatisticsVo;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
@@ -24,6 +24,7 @@ import com.czg.validator.group.DefaultGroup;
import com.czg.validator.group.InsertGroup;
import com.czg.validator.group.UpdateGroup;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -44,6 +45,10 @@ public class ProductController {
private final ProductService productService;
private final ProdConsRelationService prodConsRelationService;
private final RabbitPublisher rabbitPublisher;
@Resource
private ShopSyncService shopSyncService;
@Resource
private UProductService uProductService;
/**
* 商品-分页
@@ -65,22 +70,12 @@ public class ProductController {
public CzgResult<List<ProductDTO>> getProductList(ProductDTO param) {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
ProductDTO cacheParam = new ProductDTO();
cacheParam.setShopId(shopId);
List<ProductDTO> data = getProductCacheList(cacheParam, param);
productService.refreshProductStock(param, data);
return CzgResult.success(data);
}
private List<ProductDTO> getProductCacheList(ProductDTO cacheParam, ProductDTO param) {
List<ProductDTO> productList = productService.getProductList(cacheParam);
if (StrUtil.isNotEmpty(param.getName())) {
productList = productList.stream().filter(obj -> StrUtil.contains(obj.getName(), param.getName())).toList();
}
if (ObjUtil.isNotNull(param.getCategoryId())) {
productList = productList.stream().filter(obj -> param.getCategoryId().equals(obj.getCategoryId())).toList();
}
return productList;
List<ProductDTO> productList = productService.getProductCacheList(param);
productService.refreshProductStock(param, productList);
productList.forEach(prod -> {
prod.setIsSaleTime(uProductService.calcIsSaleTime(prod.getDays(), prod.getStartTime(), prod.getEndTime()));
});
return CzgResult.success(productList);
}
/**
@@ -109,6 +104,7 @@ public class ProductController {
Long shopId = StpKit.USER.getShopId(0L);
dto.setShopId(shopId);
productService.addProduct(dto);
asyncToBranchShop(dto.getId());
ThreadUtil.execAsync(() -> {
rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId));
});
@@ -137,6 +133,7 @@ public class ProductController {
Long shopId = StpKit.USER.getShopId(0L);
dto.setShopId(shopId);
productService.updateProduct(dto);
asyncToBranchShop(dto.getId());
ThreadUtil.execAsync(() -> {
rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId));
});
@@ -151,6 +148,9 @@ public class ProductController {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
productService.updateProductStock(param);
ThreadUtil.execAsync(() -> {
rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId));
});
return CzgResult.success();
}
@@ -168,6 +168,7 @@ public class ProductController {
AssertUtil.isNull(id, "{}不能为空", "id");
Long shopId = StpKit.USER.getShopId(0L);
productService.deleteProduct(shopId, id);
asyncToBranchShop(id);
ThreadUtil.execAsync(() -> {
rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId));
});
@@ -216,6 +217,7 @@ public class ProductController {
//@SaAdminCheckPermission("product:bind")
public CzgResult<Void> bindCons(@RequestBody @Validated({DefaultGroup.class}) ProdConsBindDTO param) {
prodConsRelationService.saveProdConsRelation(param);
asyncToBranchShop2(param.getId());
return CzgResult.success();
}
@@ -227,6 +229,7 @@ public class ProductController {
//@SaAdminCheckPermission("product:update")
public CzgResult<Void> refundToStock(@RequestBody @Validated({DefaultGroup.class}) ProdRefundToStockParam param) {
productService.refundToStock(param);
asyncToBranchShop(param.getId());
return CzgResult.success();
}
@@ -282,4 +285,44 @@ public class ProductController {
return CzgResult.success(data);
}
/**
* 商品-报损
*/
@PostMapping("sync")
@OperationLog("商品-同步主店商品信息")
//@SaAdminCheckPermission("product:sync")
public CzgResult<Void> sync() {
long shopId = StpKit.USER.getShopId(0L);
long sysUserId = StpKit.USER.getLoginIdAsLong();
boolean isEnableSync = StpKit.USER.isEnableSync(shopId);
long headShopId = StpKit.USER.getHeadShopId();
if (!isEnableSync) {
throw new CzgException("主店未开启商品资料同步功能");
}
if (shopId == headShopId) {
throw new CzgException("不存在主子店铺关系,无需同步商品信息");
}
ThreadUtil.execAsync(() -> {
shopSyncService.sync(headShopId, shopId, sysUserId);
});
CzgResult<Void> ret = CzgResult.success();
ret.setMsg("操作成功,数据正在后台同步中...");
return ret;
}
private void asyncToBranchShop(Long id) {
long shopId = StpKit.USER.getShopId(0L);
long sysUserId = StpKit.USER.getLoginIdAsLong();
ThreadUtil.execAsync(() -> {
shopSyncService.syncProductBySourceShop(shopId, id, sysUserId);
});
}
private void asyncToBranchShop2(Long id) {
long shopId = StpKit.USER.getShopId(0L);
long sysUserId = StpKit.USER.getLoginIdAsLong();
ThreadUtil.execAsync(() -> {
shopSyncService.syncConsProBySourceShop(shopId, id, sysUserId);
});
}
}

View File

@@ -1,14 +1,18 @@
package com.czg.controller.admin;
import cn.hutool.core.thread.ThreadUtil;
import com.czg.log.annotation.OperationLog;
import com.czg.product.dto.ShopProdCategoryDTO;
import com.czg.product.service.ShopProdCategoryService;
import com.czg.product.service.ShopSyncService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.utils.AssertUtil;
import com.czg.validator.group.DefaultGroup;
import com.czg.validator.group.InsertGroup;
import com.czg.validator.group.UpdateGroup;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -27,6 +31,8 @@ import java.util.List;
@RequestMapping("/admin/prod/category")
public class ShopProdCategoryController {
private final ShopProdCategoryService shopProdCategoryService;
@Resource
private ShopSyncService shopSyncService;
@GetMapping("page")
@OperationLog("商品分类-分页")
@@ -58,6 +64,7 @@ public class ShopProdCategoryController {
//@SaAdminCheckPermission("shopProdCategory:add")
public CzgResult<Void> addShopProdCategory(@RequestBody @Validated({InsertGroup.class, DefaultGroup.class}) ShopProdCategoryDTO dto) {
shopProdCategoryService.addShopProdCategory(dto);
asyncToBranchShop(dto.getId());
return CzgResult.success();
}
@@ -66,6 +73,7 @@ public class ShopProdCategoryController {
//@SaAdminCheckPermission("shopProdCategory:update")
public CzgResult<Void> updateShopProdCategory(@RequestBody @Validated({UpdateGroup.class, DefaultGroup.class}) ShopProdCategoryDTO dto) {
shopProdCategoryService.updateShopProdCategory(dto);
asyncToBranchShop(dto.getId());
return CzgResult.success();
}
@@ -86,6 +94,7 @@ public class ShopProdCategoryController {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
shopProdCategoryService.disableShopProdCategory(id);
asyncToBranchShop(id);
return CzgResult.success();
}
@@ -96,7 +105,16 @@ public class ShopProdCategoryController {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
shopProdCategoryService.enableShopProdCategory(id);
asyncToBranchShop(id);
return CzgResult.success();
}
private void asyncToBranchShop(Long id) {
long shopId = StpKit.USER.getShopId(0L);
long sysUserId = StpKit.USER.getLoginIdAsLong();
ThreadUtil.execAsync(() -> {
shopSyncService.syncCategoryBySourceShop(shopId, id, sysUserId);
});
}
}

View File

@@ -1,14 +1,19 @@
package com.czg.controller.admin;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.czg.log.annotation.OperationLog;
import com.czg.product.dto.ShopProdSpecDTO;
import com.czg.product.service.ShopProdSpecService;
import com.czg.product.service.ShopSyncService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.utils.AssertUtil;
import com.czg.validator.ValidatorUtil;
import com.czg.validator.group.DefaultGroup;
import com.czg.validator.group.InsertGroup;
import com.czg.validator.group.UpdateGroup;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
@@ -26,6 +31,9 @@ import java.util.List;
@RequestMapping("/admin/prod/spec")
public class ShopProdSpecController {
private final ShopProdSpecService shopProdSpecService;
@Resource
private ShopSyncService shopSyncService;
@GetMapping("list")
@OperationLog("商品规格-列表")
@@ -50,9 +58,8 @@ public class ShopProdSpecController {
public CzgResult<Void> addShopProdSpec(@RequestBody ShopProdSpecDTO dto) {
//效验数据
ValidatorUtil.validateEntity(dto, InsertGroup.class, DefaultGroup.class);
shopProdSpecService.addShopProdSpec(dto);
asyncToBranchShop(dto.getId());
return CzgResult.success();
}
@@ -62,9 +69,11 @@ public class ShopProdSpecController {
public CzgResult<Void> updateShopProdSpec(@RequestBody ShopProdSpecDTO dto) {
//效验数据
ValidatorUtil.validateEntity(dto, UpdateGroup.class, DefaultGroup.class);
shopProdSpecService.updateShopProdSpec(dto);
List<Long> affectedIdList = dto.getAffectedIdList();
if (CollUtil.isNotEmpty(affectedIdList)) {
affectedIdList.forEach(this::asyncToBranchShop);
}
return CzgResult.success();
}
@@ -85,6 +94,7 @@ public class ShopProdSpecController {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
shopProdSpecService.disableShopProdSpec(id);
asyncToBranchShop(id);
return CzgResult.success();
}
@@ -95,6 +105,7 @@ public class ShopProdSpecController {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
shopProdSpecService.enableShopProdSpec(id);
asyncToBranchShop(id);
return CzgResult.success();
}
@@ -103,6 +114,10 @@ public class ShopProdSpecController {
//@SaAdminCheckPermission("shopProductSpec:add")
public CzgResult<Void> quickAddShopProdSpec(@RequestBody ShopProdSpecDTO dto) {
shopProdSpecService.quickAddShopProdSpec(dto);
List<Long> affectedIdList = dto.getAffectedIdList();
if (CollUtil.isNotEmpty(affectedIdList)) {
affectedIdList.forEach(this::asyncToBranchShop);
}
return CzgResult.success();
}
@@ -120,6 +135,19 @@ public class ShopProdSpecController {
//@SaAdminCheckPermission("shopProductSpec:update")
public CzgResult<Void> quickUpdateShopProdSpec(@RequestBody ShopProdSpecDTO dto) {
shopProdSpecService.quickUpdateShopProdSpec(dto);
List<Long> affectedIdList = dto.getAffectedIdList();
if (CollUtil.isNotEmpty(affectedIdList)) {
affectedIdList.forEach(this::asyncToBranchShop);
}
return CzgResult.success();
}
private void asyncToBranchShop(Long id) {
long shopId = StpKit.USER.getShopId(0L);
long sysUserId = StpKit.USER.getLoginIdAsLong();
ThreadUtil.execAsync(() -> {
ThreadUtil.safeSleep(1000L);
shopSyncService.syncSpecBySourceShop(shopId, id, sysUserId);
});
}
}

View File

@@ -1,14 +1,18 @@
package com.czg.controller.admin;
import cn.hutool.core.thread.ThreadUtil;
import com.czg.log.annotation.OperationLog;
import com.czg.product.dto.ShopProdUnitDTO;
import com.czg.product.service.ShopProdUnitService;
import com.czg.product.service.ShopSyncService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.utils.AssertUtil;
import com.czg.validator.group.DefaultGroup;
import com.czg.validator.group.InsertGroup;
import com.czg.validator.group.UpdateGroup;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -28,6 +32,9 @@ import java.util.List;
public class ShopProdUnitController {
private final ShopProdUnitService shopProdUnitService;
@Resource
private ShopSyncService shopSyncService;
@GetMapping("page")
@OperationLog("商品单位-分页")
@@ -58,9 +65,8 @@ public class ShopProdUnitController {
@OperationLog("商品单位-新增")
//@SaAdminCheckPermission("shopProdUnit:add")
public CzgResult<Void> addShopProdUnit(@RequestBody @Validated({InsertGroup.class, DefaultGroup.class}) ShopProdUnitDTO dto) {
shopProdUnitService.addShopProdUnit(dto);
Long id = shopProdUnitService.addShopProdUnit(dto);
asyncToBranchShop(id);
return CzgResult.success();
}
@@ -68,9 +74,8 @@ public class ShopProdUnitController {
@OperationLog("商品单位-修改")
//@SaAdminCheckPermission("shopProdUnit:update")
public CzgResult<Void> updateShopProdUnit(@RequestBody @Validated({UpdateGroup.class, DefaultGroup.class}) ShopProdUnitDTO dto) {
shopProdUnitService.updateShopProdUnit(dto);
asyncToBranchShop(dto.getId());
return CzgResult.success();
}
@@ -91,6 +96,7 @@ public class ShopProdUnitController {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
shopProdUnitService.disableShopProdUnit(id);
asyncToBranchShop(id);
return CzgResult.success();
}
@@ -101,8 +107,16 @@ public class ShopProdUnitController {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
shopProdUnitService.enableShopProdUnit(id);
asyncToBranchShop(id);
return CzgResult.success();
}
private void asyncToBranchShop(Long id) {
long shopId = StpKit.USER.getShopId(0L);
long sysUserId = StpKit.USER.getLoginIdAsLong();
ThreadUtil.execAsync(() -> {
shopSyncService.syncUnitBySourceShop(shopId, id, sysUserId);
});
}
}

View File

@@ -1,8 +1,10 @@
package com.czg.controller.admin;
import cn.hutool.core.thread.ThreadUtil;
import com.czg.log.annotation.OperationLog;
import com.czg.product.dto.ShopVendorBillPayDTO;
import com.czg.product.dto.ShopVendorDTO;
import com.czg.product.service.ShopSyncService;
import com.czg.product.service.ShopVendorService;
import com.czg.product.vo.ShopVendorBillPayRecordVO;
import com.czg.product.vo.ShopVendorBillRecordVO;
@@ -15,6 +17,7 @@ import com.czg.validator.group.DefaultGroup;
import com.czg.validator.group.InsertGroup;
import com.czg.validator.group.UpdateGroup;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -33,6 +36,8 @@ import java.util.List;
@RequestMapping("/admin/product/vendor")
public class ShopVendorController {
private final ShopVendorService shopVendorService;
@Resource
private ShopSyncService shopSyncService;
/**
* 分页
@@ -77,6 +82,7 @@ public class ShopVendorController {
//@SaAdminCheckPermission("shopVendor:add")
public CzgResult<Void> addShopVendor(@RequestBody @Validated({InsertGroup.class, DefaultGroup.class}) ShopVendorDTO dto) {
shopVendorService.addShopVendor(dto);
asyncToBranchShop(dto.getId());
return CzgResult.success();
}
@@ -88,11 +94,13 @@ public class ShopVendorController {
//@SaAdminCheckPermission("shopVendor:update")
public CzgResult<Void> updateShopVendor(@RequestBody @Validated({UpdateGroup.class, DefaultGroup.class}) ShopVendorDTO dto) {
shopVendorService.updateShopVendor(dto);
asyncToBranchShop(dto.getId());
return CzgResult.success();
}
/**
* 删除
*
* @param id 供应商id
*/
@DeleteMapping("{id}")
@@ -102,46 +110,51 @@ public class ShopVendorController {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
shopVendorService.deleteShopVendor(id);
asyncToBranchShop(id);
return CzgResult.success();
}
/**
* 供应商账单统计
*
* @return 统计信息
*/
@GetMapping("summary")
@OperationLog("供应商账单-统计")
// @OperationLog("供应商账单-统计")
public CzgResult<ShopVendorSummaryVO> summary() {
return CzgResult.success(shopVendorService.summary(StpKit.USER.getShopId()));
}
/**
* 账单列表
*
* @return 账单列表
*/
@GetMapping("/bill")
@OperationLog("供应商账单-列表")
public CzgResult<Page<ShopVendorBillVO>> bill() {
return CzgResult.success(shopVendorService.billList(StpKit.USER.getShopId()));
// @OperationLog("供应商账单-列表")
public CzgResult<Page<ShopVendorBillVO>> bill(@RequestParam(required = false) String key) {
return CzgResult.success(shopVendorService.billList(StpKit.USER.getShopId(), key));
}
/**
* 账单记录
*
* @return 记录list
*/
@GetMapping("/bill/record")
@OperationLog("供应商账单-列表")
public CzgResult<Page<ShopVendorBillRecordVO>> bill(@RequestParam Integer vendorId) {
return CzgResult.success(shopVendorService.billRecord(StpKit.USER.getShopId(), vendorId));
// @OperationLog("供应商账单-列表")
public CzgResult<Page<ShopVendorBillRecordVO>> bill(@RequestParam Integer vendorId, @RequestParam(required = false) String key) {
return CzgResult.success(shopVendorService.billRecord(StpKit.USER.getShopId(), vendorId, key));
}
/**
* 账单支付
*
* @return 记录list
*/
@PostMapping("/bill/pay")
@OperationLog("供应商账单-付款")
// @OperationLog("供应商账单-付款")
public CzgResult<Boolean> pay(@RequestBody @Validated ShopVendorBillPayDTO payDTO) {
return CzgResult.success(shopVendorService.pay(StpKit.USER.getShopId(), payDTO));
}
@@ -149,12 +162,21 @@ public class ShopVendorController {
/**
* 账单支付记录
*
* @return 记录list
*/
@GetMapping("/bill/pay/record")
@OperationLog("供应商账单-付款记录")
// @OperationLog("供应商账单-付款记录")
public CzgResult<Page<ShopVendorBillPayRecordVO>> payRecord(@RequestParam Long flowId) {
return CzgResult.success(shopVendorService.payRecord(StpKit.USER.getShopId(), flowId));
}
private void asyncToBranchShop(Long id) {
long shopId = StpKit.USER.getShopId(0L);
long sysUserId = StpKit.USER.getLoginIdAsLong();
ThreadUtil.execAsync(() -> {
shopSyncService.syncVendorBySourceShop(shopId, id, sysUserId);
});
}
}

View File

@@ -1,7 +1,7 @@
package com.czg.controller.user;
import com.czg.enums.YesNoEnum;
import com.czg.product.param.ShopProductSkuParam;
import com.czg.product.service.ProdGroupService;
import com.czg.product.service.UProductService;
import com.czg.product.vo.ShopGroupProductVo;
import com.czg.product.vo.ShopProductInfoVo;
@@ -9,6 +9,7 @@ import com.czg.product.vo.ShopProductSkuInfoVo;
import com.czg.product.vo.ShopProductVo;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.utils.AssertUtil;
import com.czg.validator.ValidatorUtil;
import com.czg.validator.group.DefaultGroup;
@@ -33,7 +34,7 @@ import java.util.Map;
@RequestMapping("/user/product")
public class UProductController {
private final UProductService uProductService;
private final ProdGroupService prodGroupService;
private final RedisService redisService;
/**
* 小程序点餐-热销商品列表
@@ -61,7 +62,11 @@ public class UProductController {
uProductService.refreshProductStock(productStock, item.getProductList());
item.getProductList().forEach(prod -> {
prod.setIsSaleTime(uProductService.calcIsSaleTime(prod.getDays(), prod.getStartTime(), prod.getEndTime()));
prod.setIsSaleTime(uProductService.calcIsSaleTime(item.getUseTime(), item.getSaleStartTime(), item.getSaleEndTime()));
prod.setIsSaleTime(uProductService.calcIsSaleTime(prod.getIsSaleTime(), item.getUseTime(), item.getSaleStartTime(), item.getSaleEndTime()));
if (item.getUseTime() == YesNoEnum.YES.value()) {
prod.setStartTime(item.getSaleStartTime());
prod.setEndTime(item.getSaleEndTime());
}
});
});
return CzgResult.success(list);

View File

@@ -1,5 +1,7 @@
package com.czg.service;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -598,4 +600,54 @@ public class RedisService {
return redisTemplate.opsForList().rightPop(key);
}
/**
* 右模糊查找key
*
* @param key 模糊匹配的key前缀
* @return 匹配的keys
*/
public Set<String> rightLikeKey(String key) {
return redisTemplate.keys(key + "*");
}
/**
* JsonString缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean setJsonStr(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, JSON.toJSONString(value, JSONWriter.Feature.WriteMapNullValue));
return true;
} catch (Exception e) {
log.error("redis error:{}", e + "");
return false;
}
}
/**
* JsonString缓存获取
*
* @param key 键
* @return 值
*/
public String getJsonStr(String key) {
return key == null ? null : (String) redisTemplate.opsForValue().get(key);
}
/**
* JsonString缓存获取
*
* @param key 键
* @return 值
*/
public <T> List<T> getJsonToBeanList(String key, Class<T> type) {
String jsonStr = getJsonStr(key);
if (jsonStr == null) {
return null;
}
return JSON.parseArray(jsonStr, type);
}
}

View File

@@ -28,6 +28,11 @@
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
</dependency>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring-boot3-starter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>

View File

@@ -16,7 +16,9 @@ import cn.dev33.satoken.stp.StpLogic;
import cn.hutool.core.util.StrUtil;
import com.czg.exception.ApiNotPrintException;
import com.czg.exception.CzgException;
import com.mybatisflex.core.row.DbChain;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.Map;
@@ -25,6 +27,7 @@ import java.util.function.Consumer;
/**
* @author Administrator
*/
@Slf4j
@Getter
public class MyStpLogic {
public static final StpLogic CLIENT_LOGIC = new StpLogic("client");
@@ -53,6 +56,34 @@ public class MyStpLogic {
}
}
/**
* 身份切换
*
* @param id 用户id
* @param account 账户名
* @param shopId 店铺id
* @param shopName 店铺名称
* @param loginType 登录类型
* @param isAdmin 是否管理员
*/
public void switchTo(boolean isMain, Long id, String account, Long shopId, String shopName, LoginType loginType, boolean isAdmin) {
StpLogic logic = getLogic();
long headId = logic.getLoginIdAsLong();
logic.getSaTokenDao().set(splicingKeyTokenValue(logic.getTokenValue()), id.toString(), logic.getTokenTimeout());
SaSession session = logic.getSession();
if (session == null) {
logic.createLoginSession(id);
session = logic.getSession();
}
Object parentId1 = session.get("headId");
if (!isMain && parentId1 == null) {
session.set("headId", headId);
}
session.set("userId", id).set("isAdmin", isAdmin).set("isManager", loginType.equals(LoginType.MANAGER))
.set("loginType", loginType).set("account", account).set("shopId", shopId).set("shopName", shopName);
}
/**
* @param id 登录账号id
* @param shopName 店铺名称
@@ -83,6 +114,7 @@ public class MyStpLogic {
SaManager.getSaTokenDao().set(SaManager.getConfig().getTokenName() + ":" + token, String.valueOf(id), SaManager.getConfig().getTimeout());
}
/**
* 获取当前登录账号名称 管理端为用户账号 客户端为openId
*
@@ -104,6 +136,16 @@ public class MyStpLogic {
return shopName instanceof String s ? s : null;
}
/**
* 获取主店铺id
*
* @return id
*/
public Long getHeadId() {
Object headId = getLogic().getSession().get("headId");
return headId == null ? null : Long.parseLong(headId.toString());
}
/**
* 获取店铺id
*
@@ -160,6 +202,62 @@ public class MyStpLogic {
return shopId == null ? defaultVal : shopId;
}
/**
* 获取适用的店铺id主分店模式使用若全部开启同步返回主店id。若未开启同步则返回分店id
*
* @return 主店id
*/
public Long getUsableShopId() {
Long shopId = getShopId(0L);
Long mainId = DbChain.table("tb_shop_config").select("main_id").where("id = ? and is_enable_prod_sync = 1 and is_enable_vip_sync = 1 and is_enable_cons_sync = 1", shopId).objAs(Long.class);
if (mainId != null) {
return mainId;
}
return shopId;
}
/**
* 获取主店id
*
* @return 主店id
*/
public Long getHeadShopId() {
Long shopId = getShopId(0L);
Long mainId = DbChain.table("tb_shop_config").select("main_id").where("id = ?", shopId).objAs(Long.class);
if (mainId != null) {
return mainId;
}
return shopId;
}
/**
* 获取主店id
*
* @param shopId 店铺id
* @return 主店id
*/
public Long getHeadShopId(Long shopId) {
Long mainId = DbChain.table("tb_shop_config").select("main_id").where("id = ?", shopId).objAs(Long.class);
if (mainId != null) {
return mainId;
}
return shopId;
}
/**
* 是否启用同步功能
*
* @param shopId 店铺id
* @return 主店id
*/
public boolean isEnableSync(Long shopId) {
Integer isEnableProdSync = DbChain.table("tb_shop_config").select("is_enable_prod_sync").where("id = ?", shopId).objAs(Integer.class);
if (isEnableProdSync == null) {
return false;
}
return isEnableProdSync == 1;
}
/**
* 校验是否为管理端登录
*/
@@ -901,11 +999,6 @@ public class MyStpLogic {
}
public void switchTo(Object loginId) {
getLogic().switchTo(loginId);
}
public void endSwitch() {
getLogic().endSwitch();
}

View File

@@ -0,0 +1,58 @@
package com.czg.account.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 分店管理DTO
* @author tankaikai
* @since 2025-04-07 14:12
*/
@Data
public class ShopBranchDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 分店id
*/
private Long id;
/**
* 店铺名称
*/
private String shopName;
/**
* 店铺类型 单店--only 连锁店--chain--加盟店join (对应原来 type
*/
private String shopType;
/**
* 账号
*/
private String account;
/**
* 联系电话
*/
private String phone;
/**
* 是否启用商品同步 1-是 0-否
*/
private Integer isEnableProdSync;
/**
* 是否启用会员同步 1-是 0-否
*/
private Integer isEnableVipSync;
/**
* 是否启用耗材同步 1-是 0-否
*/
private Integer isEnableConsSync;
/**
* 是否允许账号登录 1-是 0-否
*/
private Integer isAllowAccountLogin;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,81 @@
package com.czg.account.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 店铺配置扩展
*
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-04-03
*/
@Data
public class ShopConfigDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 店铺id
*/
private Long id;
/**
* 主店id
*/
private Long mainId;
/**
* 是否启用商品同步 1-是 0-否
*/
private Integer isEnableProdSync;
/**
* 是否启用会员同步 1-是 0-否
*/
private Integer isEnableVipSync;
/**
* 是否启用耗材同步 1-是 0-否
*/
private Integer isEnableConsSync;
/**
* 是否允许账号登录 1-是 0-否
*/
private Integer isAllowAccountLogin;
/**
* 备注
*/
private String remark;
/**
* 是否允许会员自定义金额 1-允许 0-不允许
*/
private Integer isCustomAmount;
/**
* 是否开启退款密码 1-启用 0-禁用
*/
private Integer isReturnPwd;
/**
* 是否开启会员充值密码 1-启用 0-禁用
*/
private Integer isMemberInPwd;
/**
* 是否开启会员退款密码 1-启用 0-禁用
*/
private Integer isMemberReturnPwd;
/**
* 是否免除桌位费 1-是 0-否
*/
private Integer isTableFee;
/**
* 是否启用会员价 1-是 0-否
*/
private Integer isMemberPrice;
/**
* 是否允许会员余额支付 1-是 0-否
*/
private Integer isAccountPay;
/**
* 分店数据同步方式 auto-自动同步 manual-手动同步
*/
private String branchDataSyncMethod;
}

View File

@@ -0,0 +1,64 @@
package com.czg.account.dto;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.alibaba.fastjson2.annotation.JSONField;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 实体类。
*
* @author zs
* @since 2025-04-07
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SyncNoticeDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long id;
/**
* 商品名称或耗材名称
*/
private String name;
/**
* 来源id
*/
private Long sourceId;
/**
* 操作用户id
*/
private Long sysUserId;
/**
* 通知类型 0 商品变动 1 耗材变动
*/
private Integer type;
/**
* 是否已读1已读
*/
private Integer isRead;
/**
* 店铺id
*/
private Long shopId;
/**
* 创建时间
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
}

View File

@@ -1,6 +1,7 @@
package com.czg.account.dto.pad;
import com.czg.product.entity.Product;
import com.czg.product.vo.ProductVO;
import lombok.Data;
import java.util.List;
@@ -13,5 +14,5 @@ public class PadDetailDTO {
private Long id;
private Long padLayoutId;
private List<Long> productIdList;
private List<Product> productList;
private List<ProductVO> productList;
}

View File

@@ -0,0 +1,27 @@
package com.czg.account.dto.shopinfo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 下拉店铺列表DTO
* @author tankaikai
* @since 2025-04-07 13:45
*/
@Data
public class ShopBranchSelectDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 店铺ID
*/
private Long shopId;
/**
* 店铺名称
*/
private String shopName;
}

View File

@@ -45,4 +45,12 @@ public class ShopInfoAddDTO {
private String districts;
private String provinces;
private String address;
/**
* 是否为主店
*/
private Integer isHeadShop;
/**
* 主店id
*/
private Long mainId;
}

View File

@@ -87,7 +87,7 @@ public class ShopInfoEditDTO {
/**
* 主店id
*/
private Integer mainId;
private Long mainId;
/**
* 店铺口号
@@ -241,4 +241,8 @@ public class ShopInfoEditDTO {
* 店铺激活码
*/
private String activateCode;
/**
* 是否为主店 1-是 0-否
*/
private Integer isHeadShop;
}

View File

@@ -0,0 +1,85 @@
package com.czg.account.entity;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 店铺配置扩展
*
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-04-03
*/
@Data
@Table("tb_shop_config")
public class ShopConfig implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 店铺id
*/
@Id(keyType = KeyType.None)
private Long id;
/**
* 主店id
*/
private Long mainId;
/**
* 是否启用商品同步 1-是 0-否
*/
private Integer isEnableProdSync;
/**
* 是否启用会员同步 1-是 0-否
*/
private Integer isEnableVipSync;
/**
* 是否启用耗材同步 1-是 0-否
*/
private Integer isEnableConsSync;
/**
* 是否允许账号登录 1-是 0-否
*/
private Integer isAllowAccountLogin;
/**
* 备注
*/
private String remark;
/**
* 是否允许会员自定义金额 1-允许 0-不允许
*/
private Integer isCustomAmount;
/**
* 是否开启退款密码 1-启用 0-禁用
*/
private Integer isReturnPwd;
/**
* 是否开启会员充值密码 1-启用 0-禁用
*/
private Integer isMemberInPwd;
/**
* 是否开启会员退款密码 1-启用 0-禁用
*/
private Integer isMemberReturnPwd;
/**
* 是否免除桌位费 1-是 0-否
*/
private Integer isTableFee;
/**
* 是否启用会员价 1-是 0-否
*/
private Integer isMemberPrice;
/**
* 是否允许会员余额支付 1-是 0-否
*/
private Integer isAccountPay;
/**
* 分店数据同步方式 auto-自动同步 manual-手动同步
*/
private String branchDataSyncMethod;
}

View File

@@ -38,7 +38,7 @@ public class ShopInfo implements Serializable {
/**
* 主店id
*/
private Integer mainId;
private Long mainId;
/**
* 店铺口号
@@ -90,7 +90,7 @@ public class ShopInfo implements Serializable {
*/
private String detail;
/**
* 注册类型
* 注册类型(经营模式)
* 快餐版 先付 munchies
* 餐饮版 先付/后付 restaurant
*/
@@ -187,46 +187,11 @@ public class ShopInfo implements Serializable {
*/
private String address;
/**
* 是否允许会员自定义金额 1 允许 0 不允许
*/
private Integer isCustomAmount;
/**
* 是否开启退款密码 1 启用 0 禁用
*/
private Integer isReturnPwd;
/**
* 是否开启会员充值密码 1 启用 0 禁用
*/
private Integer isMemberInPwd;
/**
* 是否开启会员退款密码 1 启用 0 禁用
*/
private Integer isMemberReturnPwd;
/**
* 是否免除桌位费 0否1是
*/
private Integer isTableFee;
/**
* 是否开启会员余额支付
*/
private Integer isAccountPay;
/**
* 桌位费
*/
private BigDecimal tableFee;
/**
* 是否启用会员价 0否1是
*/
private Integer isMemberPrice;
/**
* 就餐模式 堂食 dine-in 外带 take-out
*/
@@ -271,5 +236,69 @@ public class ShopInfo implements Serializable {
* 税率
*/
private String taxAmount;
/**
* 是否主店 1-是 0-否
*/
private Integer isHeadShop;
/**
* 是否启用商品同步 1-是 0-否
*/
@Column(ignore = true)
private Integer isEnableProdSync;
/**
* 是否启用会员同步 1-是 0-否
*/
@Column(ignore = true)
private Integer isEnableVipSync;
/**
* 是否启用耗材同步 1-是 0-否
*/
@Column(ignore = true)
private Integer isEnableConsSync;
/**
* 是否允许账号登录 1-是 0-否
*/
@Column(ignore = true)
private Integer isAllowAccountLogin;
/**
* 是否允许会员自定义金额 1-允许 0-不允许
*/
@Column(ignore = true)
private Integer isCustomAmount;
/**
* 是否开启退款密码 1-启用 0-禁用
*/
@Column(ignore = true)
private Integer isReturnPwd;
/**
* 是否开启会员充值密码 1-启用 0-禁用
*/
@Column(ignore = true)
private Integer isMemberInPwd;
/**
* 是否开启会员退款密码 1-启用 0-禁用
*/
@Column(ignore = true)
private Integer isMemberReturnPwd;
/**
* 是否免除桌位费 1-是 0-否
*/
@Column(ignore = true)
private Integer isTableFee;
/**
* 是否启用会员价 1-是 0-否
*/
@Column(ignore = true)
private Integer isMemberPrice;
/**
* 是否允许会员余额支付 1-是 0-否
*/
@Column(ignore = true)
private Integer isAccountPay;
/**
* 主店名称
*/
@Column(ignore = true)
private String headShopName;
}

View File

@@ -125,4 +125,8 @@ public class ShopUser implements Serializable {
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
/**
* 已经合并过来的用户信息jsonArray格式,[{"id":1,"shopId":2,...},{"id":1,"shopId":2,...}]
*/
private String mergedUsers;
}

View File

@@ -0,0 +1,82 @@
package com.czg.account.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 实体类。
*
* @author zs
* @since 2025-04-07
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("tb_sync_notice")
public class SyncNotice implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 操作用户id
*/
private Long sysUserId;
/**
* 是否已读1已读
*/
private Integer isRead;
/**
* 店铺id
*/
private Long shopId;
/**
* 标题 数据同步/数据变动/库存预警
*/
private String title;
/**
* 消息内容
* {
* "title": "XX同步/变动",//商品 单位 规格 分组 耗材 耗材分组
* "number": "XX个",
* "map": [
* {
* "id": 1,
* "name": ""
* }
* ]
* }
* {
* "title": "XX库存不足" //商品/耗材
* }
*/
private String content;
private String extraJson;
/**
* 创建时间
*/
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
private LocalDateTime readTime;
}

View File

@@ -0,0 +1,47 @@
package com.czg.account.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
import java.util.List;
/**
* 分店数据同步方式枚举
*
* @author tankaikai
* @since 2025-04-03 16:53
*/
@Getter
@RequiredArgsConstructor
public enum BranchDataSyncMethodEnum {
/**
* 实时自动同步
*/
AUTO("auto", "实时自动同步"),
/**
* 手动同步
*/
MANUAL("manual", "手动同步");
private final String value;
private final String text;
public static List<String> getValues() {
return Arrays.stream(values()).map(BranchDataSyncMethodEnum::getValue).toList();
}
public static String getText(String value) {
BranchDataSyncMethodEnum item = Arrays.stream(values()).filter(obj -> value.equals(obj.getValue())).findFirst().orElse(null);
if (item != null) {
return item.getText();
}
return null;
}
public static boolean checkValue(String value) {
return getValues().contains(value);
}
}

View File

@@ -0,0 +1,48 @@
package com.czg.account.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
import java.util.List;
/**
* 店铺经营模式枚举
*
* @author tankaikai
* @since 2025-04-03 16:53
*/
@Getter
@RequiredArgsConstructor
public enum ShopTypeEnum {
/**
* 单店
*/
ONLY("only", "单店"),
/**
* 连锁店
*/
CHAIN("chain", "连锁店"),
/**
* 加盟店
*/
JOIN("join", "加盟店"),
;
private final String value;
private final String text;
public static List<String> getValues() {
return Arrays.stream(values()).map(ShopTypeEnum::getValue).toList();
}
public static String getText(String value) {
ShopTypeEnum item = Arrays.stream(values()).filter(obj -> value.equals(obj.getValue())).findFirst().orElse(null);
if (item != null) {
return item.getText();
}
return null;
}
}

View File

@@ -0,0 +1,30 @@
package com.czg.account.param;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 分店查询入参
* @author tankaikai
* @since 2025-04-07 18:02
*/
@Data
public class ShopBranchParam implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 分店名称
*/
private String branchShopName;
/**
* 店铺ID
*/
@JSONField(serialize = false)
private Long shopId;
}

View File

@@ -11,4 +11,10 @@ public interface AuthorizationService {
Object getCaptcha();
LoginVO login(SysLoginDTO loginDTO, String platformType);
/**
* 切换登录用户
* @param sysUserId 系统用户id
*/
void switchTo(Long sysUserId);
}

View File

@@ -0,0 +1,54 @@
package com.czg.account.service;
import com.czg.account.dto.ShopBranchDTO;
import com.czg.account.param.ShopBranchParam;
import com.mybatisflex.core.paginate.Page;
/**
* 分店管理Service
*
* @author tankaikai
* @since 2025-04-07 14:09
*/
public interface ShopBranchService {
/**
* 查询分店列表
*
* @param param 查询入参
* @return 分店列表
*/
Page<ShopBranchDTO> findPage(ShopBranchParam param);
/**
* 设计数据同步方式
*
* @param shopId 主店id
* @param dataSyncMethod 数据同步方式 {@link com.czg.account.enums.BranchDataSyncMethodEnum}
*/
void settingDataSyncMethod(Long shopId, String dataSyncMethod);
/**
* 数据同步启用
* @param branchShopId 分店id
*/
void dataSyncEnable(Long branchShopId);
/**
* 账号启用
* @param branchShopId 分店id
*/
void accountEnable(Long branchShopId);
/**
* 账号禁用
* @param branchShopId 分店id
*/
void accountDisable(Long branchShopId);
/**
* 查询是否允许分店账号登录
* @param branchShopId 分店id
* @return 是否允许分店账号登录 {@code true} 允许,{@code false} 不允许
*/
boolean isAllowAccountLogin(Long branchShopId);
}

View File

@@ -0,0 +1,14 @@
package com.czg.account.service;
import com.czg.account.entity.ShopConfig;
import com.mybatisflex.core.service.IService;
/**
* 店铺配置扩展
*
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-04-03
*/
public interface ShopConfigService extends IService<ShopConfig> {
}

View File

@@ -6,11 +6,13 @@ import com.czg.account.entity.ShopInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import java.util.List;
/**
* @author Administrator
*/
public interface ShopInfoService extends IService<ShopInfo> {
Page<ShopInfo> get(PageDTO pageDTO, String shopName, Integer status);
Page<ShopInfo> get(PageDTO pageDTO, String shopName, Integer status, Integer isHeadShop);
Boolean add(ShopInfoAddDTO shopInfoAddDTO);
@@ -24,4 +26,5 @@ public interface ShopInfoService extends IService<ShopInfo> {
Page<ShopInfoSubVO> getSubList(String lat, String lng, float distance);
List<ShopBranchSelectDTO> findShopBranch(Long shopId);
}

View File

@@ -0,0 +1,17 @@
package com.czg.account.service;
/**
* 店铺用户同步Service
* @author tankaikai
* @since 2025-04-08 10:17
*/
public interface ShopUserSyncService {
/**
* 同步合并主分店会员信息
*
* @param headShopId 主店id
* @param branchShopId 分店id
*/
void syncMergeShopUser(Long headShopId, Long branchShopId);
}

View File

@@ -0,0 +1,56 @@
package com.czg.account.service;
import com.czg.product.dto.SyncNoticeReadDTO;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import com.czg.account.entity.SyncNotice;
import java.util.List;
/**
* 服务层。
*
* @author zs
* @since 2025-04-07
*/
public interface SyncNoticeService extends IService<SyncNotice> {
/**
* 添加消息
*
* @param shopId 店铺id
* @param sysUserId 操作用户id
* @param name 商品/耗材名称
* @param id 商品/耗材id
* @param type 0 商品新增 1 商品编辑 2 耗材新增 3 耗材编辑
*/
void addNotice(Long shopId, Long sysUserId, String name, Long id, Integer type);
/**
*
* @param shopId 店铺ID
* @param sysUserId 操作人Id
* @param title 标题 数据同步/数据变动/库存预警
* @param content 消息内容
* {
* "title": "XX同步/变动",//商品 单位 规格 分组 耗材 耗材分组
* "number": "XX个",
* "map": [
* {
* "id": 1,
* "name": ""
* }
* ]
* }
* {
* "title": "XX库存不足" //商品/耗材
* }
*
* @param extraJson 扩展数据
*/
void addNotice(Long shopId, Long sysUserId, String title, String content, String extraJson);
Page<SyncNotice> pageInfo(Long shopId, String name, String startTime, String endTime, String title, Integer isRead);
Boolean read(Long shopId, SyncNoticeReadDTO syncNoticeReadDTO);
}

View File

@@ -23,7 +23,6 @@ import lombok.NoArgsConstructor;
* @since 2025-02-13
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table("tb_order_info")
@@ -128,6 +127,10 @@ public class OrderInfo implements Serializable {
* 台桌名称
*/
private String tableName;
/**
* 退款方式 现金退款-cash 原路退回-payBack
*/
private String refundType;
/**
* 订单类型-

View File

@@ -1,7 +1,6 @@
package com.czg.order.entity;
import com.alibaba.fastjson2.annotation.JSONField;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
@@ -141,7 +140,6 @@ public class ShopOrderStatistic implements Serializable {
/**
* 新增会员数
*/
@Column(ignore = true)
private Long newMemberCount = 0L;
/**
* 店铺id

View File

@@ -3,16 +3,15 @@ package com.czg.order.entity;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Date;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 实体类。
*

View File

@@ -3,16 +3,15 @@ package com.czg.order.entity;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Date;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 台桌订单统计表 实体类。
*
@@ -32,8 +31,22 @@ public class ShopTableOrderStatistic implements Serializable {
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 台桌id
*/
private Long tableId;
/**
* 台桌id
*/
private String tableCode;
/**
* 台桌名称
*/
private String tableName;
/**
* 区域名称
*/
private String areaName;
/**
* 订单数量
*/
@@ -56,7 +69,7 @@ public class ShopTableOrderStatistic implements Serializable {
/**
* 退款数量
*/
private long refundCount;
private Long refundCount;
/**
* 退款金额
*/

View File

@@ -34,7 +34,6 @@ public class DataSummaryProductSaleParam implements Serializable {
/**
* 店铺id
*/
@JSONField(serialize = false)
private Long shopId;
/**
* 开始日期

View File

@@ -1,6 +1,5 @@
package com.czg.order.param;
import com.alibaba.fastjson2.annotation.JSONField;
import com.czg.validator.group.DefaultGroup;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@@ -33,7 +32,6 @@ public class DataSummaryTradeParam implements Serializable {
/**
* 店铺id
*/
@JSONField(serialize = false)
private Long shopId;
}

View File

@@ -1,6 +1,5 @@
package com.czg.order.param;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import java.io.Serial;
@@ -20,7 +19,6 @@ public class SaleSummaryCountParam implements Serializable {
/**
* 店铺id
*/
@JSONField(serialize = false)
private Long shopId;
/**
* 商品名称

View File

@@ -1,6 +1,5 @@
package com.czg.order.param;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import java.io.Serial;
@@ -29,7 +28,6 @@ public class TableSummaryParam implements Serializable {
/**
* 店铺id
*/
@JSONField(serialize = false)
private Long shopId;
}

View File

@@ -18,7 +18,9 @@ import java.util.List;
*/
public interface DataSummaryService {
ShopOrderStatistic getTradeData(DataSummaryTradeParam param);
ShopOrderStatistic getArchiveTradeData(DataSummaryTradeParam param);
ShopOrderStatistic getRealTimeTradeData(DataSummaryTradeParam param);
Page<DataSummaryProductSaleRankingVo> getProductSaleRankingPage(DataSummaryProductSaleParam param);

View File

@@ -1,7 +1,8 @@
package com.czg.order.service;
import com.mybatisflex.core.service.IService;
import cn.hutool.core.date.DateTime;
import com.czg.order.entity.ShopOrderStatistic;
import com.mybatisflex.core.service.IService;
/**
* 服务层。
@@ -11,6 +12,6 @@ import com.czg.order.entity.ShopOrderStatistic;
*/
public interface ShopOrderStatisticService extends IService<ShopOrderStatistic> {
void statistic();
void statistic(DateTime dateTime);
}

View File

@@ -1,7 +1,8 @@
package com.czg.order.service;
import com.mybatisflex.core.service.IService;
import cn.hutool.core.date.DateTime;
import com.czg.order.entity.ShopProdStatistic;
import com.mybatisflex.core.service.IService;
/**
* 服务层。
@@ -11,6 +12,6 @@ import com.czg.order.entity.ShopProdStatistic;
*/
public interface ShopProdStatisticService extends IService<ShopProdStatistic> {
void statistic();
void statistic(DateTime dateTime);
}

View File

@@ -1,8 +1,9 @@
package com.czg.order.service;
import cn.hutool.core.date.DateTime;
import com.czg.order.entity.ShopTableOrderStatistic;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import com.czg.order.entity.ShopTableOrderStatistic;
import java.math.BigDecimal;
@@ -25,5 +26,5 @@ public interface ShopTableOrderStatisticService extends IService<ShopTableOrderS
*/
boolean addInfo(long shopId, long tableId, long count, BigDecimal amount);
void statistic();
void statistic(DateTime dateTime);
}

View File

@@ -5,7 +5,6 @@ import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@@ -26,27 +25,4 @@ public class DataSummaryDateAmountVo implements Serializable {
*/
private List<TotalVo> total = new ArrayList<>();
/**
* TotalVo
*/
@NoArgsConstructor
@Data
public static class TotalVo {
/**
* 实收金额
*/
private BigDecimal actualAmount = BigDecimal.ZERO;
/**
* 优惠金额
*/
private BigDecimal discountAmount = BigDecimal.ZERO;
/**
* 订单金额
*/
private BigDecimal orderAmount = BigDecimal.ZERO;
/**
* 日期
*/
private String tradeDay;
}
}

View File

@@ -19,6 +19,11 @@ public class DataSummaryProductSaleRankingVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 商品名称
*/
private Long productId;
/**
* 商品名称
*/
@@ -34,4 +39,14 @@ public class DataSummaryProductSaleRankingVo implements Serializable {
*/
private BigDecimal amount;
/**
* 退单量
*/
private BigDecimal refundCount;
/**
* 退单金额
*/
private BigDecimal refundAmount;
}

View File

@@ -71,6 +71,10 @@ public class OrderInfoVo implements Serializable {
* miniapp小程序
*/
private String orderType;
/**
* 退款方式 现金退款-cash 原路退回-payBack
*/
private String refundType;
/**
* 平台类型 pc 收银机客户端 wechat 微信小程序 alipay 支付宝小程序 admin-pc PC管理端 admin-app APP管理端

View File

@@ -32,6 +32,11 @@ public class TableSummaryInfoVo implements Serializable {
@ExcelIgnore
@JSONField(serialize = false)
private Long lineNum;
/**
* 台桌id
*/
@ExcelIgnore
private Long tableId;
/**
* 台桌码
*/

View File

@@ -0,0 +1,38 @@
package com.czg.order.vo;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* 销售趋势柱状图 左下
* @author tankaikai
* @since 2025-03-07 16:08
*/
@NoArgsConstructor
@Data
public class TotalVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 实收金额
*/
private BigDecimal actualAmount = BigDecimal.ZERO;
/**
* 优惠金额
*/
private BigDecimal discountAmount = BigDecimal.ZERO;
/**
* 订单金额
*/
private BigDecimal orderAmount = BigDecimal.ZERO;
/**
* 日期
*/
private String tradeDay;
}

View File

@@ -97,6 +97,7 @@ public class ConsStockFlowDTO implements Serializable {
* 商品id
*/
private Long productId;
private String productName;
/**
* sku id
*/
@@ -127,4 +128,6 @@ public class ConsStockFlowDTO implements Serializable {
*/
private String remark;
}
private String vendorName;
}

View File

@@ -22,10 +22,6 @@ public class ProdConsRelationDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
private Long id;
/**
* 店铺id
*/

View File

@@ -12,6 +12,7 @@ import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
/**
* 商品规格
@@ -81,5 +82,9 @@ public class ShopProdSpecDTO extends TreeNode<ShopProdSpecDTO> implements Serial
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
/**
* 受影响的规格id列表
*/
@JSONField(serialize = false)
private List<Long> affectedIdList;
}

View File

@@ -0,0 +1,17 @@
package com.czg.product.dto;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.util.List;
/**
* @author Administrator
*/
@Data
public class SyncNoticeReadDTO {
/**
* 消息id
*/
private List<Long> noticeIdList;
}

View File

@@ -28,6 +28,10 @@ public class ConsGroup implements Serializable {
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 同步id
*/
private Long syncId;
/**
* 店铺id
*/

View File

@@ -29,6 +29,10 @@ public class ConsInfo implements Serializable {
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 同步id
*/
private Long syncId;
/**
* 耗材分组id
*/

View File

@@ -24,22 +24,20 @@ public class ProdConsRelation implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 店铺id
*/
@Id(keyType = KeyType.None)
private Long shopId;
/**
* 商品id
*/
@Id(keyType = KeyType.None)
private Long productId;
/**
* 耗材id
*/
@Id(keyType = KeyType.None)
private Long consInfoId;
/**
* 单位消耗值

View File

@@ -29,6 +29,10 @@ public class ProdGroup implements Serializable {
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 同步id
*/
private Long syncId;
/**
* 分组名称
*/

View File

@@ -29,6 +29,10 @@ public class ProdSku implements Serializable {
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 同步id
*/
private Long syncId;
/**
* 店铺id
*/

View File

@@ -30,6 +30,10 @@ public class Product implements Serializable {
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 同步id
*/
private Long syncId;
/**
* 商品分类
*/

View File

@@ -28,6 +28,10 @@ public class ShopProdCategory implements Serializable {
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 同步id
*/
private Long syncId;
/**
* 分类名称
*/

View File

@@ -28,6 +28,10 @@ public class ShopProdSpec implements Serializable {
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 同步id
*/
private Long syncId;
/**
* 规格名称
*/

View File

@@ -28,6 +28,10 @@ public class ShopProdUnit implements Serializable {
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 同步id
*/
private Long syncId;
/**
* 单位名称
*/

View File

@@ -32,6 +32,7 @@ public class ShopVendor implements Serializable {
* 店铺Id
*/
private Long shopId;
private Long syncId;
/**
* 排序
*/

View File

@@ -1,5 +1,7 @@
package com.czg.product.service;
import com.czg.product.vo.ProductVO;
import java.util.List;
import java.util.Map;
@@ -36,4 +38,13 @@ public interface ProductRpcService {
* @param dataList 库存恢复数据
*/
void orderRefundReturnStock(Long shopId, Long orderId, List<Map<String, Object>> dataList);
List<ProductVO> listAndLowPrice(Long shopId, List<Long> productIds);
/**
* 清除分类商品缓存
* @param shopId 店铺id
* @param categoryId 商品分类id
*/
void cleanCategoryProduct(Long shopId, Long categoryId);
}

View File

@@ -33,6 +33,19 @@ public interface ProductService extends IService<Product> {
*/
List<ProductDTO> getProductList(ProductDTO param);
/**
* 从缓存里面获取商品列表
*
* @param param 查询参数
* @return 商品列表数据
*/
List<ProductDTO> getProductCacheList(ProductDTO param);
/**
* 清除某个商品分类的缓存
*/
void clearProductCache(Long... categoryIds);
/**
* 获取商品详情
*
@@ -127,4 +140,5 @@ public interface ProductService extends IService<Product> {
* @param records 商品数据集合
*/
void refreshProductStock(ProductDTO param, List<ProductDTO> records);
}

View File

@@ -25,6 +25,7 @@ public interface ShopProdUnitService extends IService<ShopProdUnit> {
/**
* 获取商品单位列表
*
* @param param 查询参数
* @return 商品单位列表数据
*/
@@ -32,6 +33,7 @@ public interface ShopProdUnitService extends IService<ShopProdUnit> {
/**
* 获取商品单位详情
*
* @param id 商品单位ID
* @return 商品单位详情数据
*/
@@ -41,8 +43,9 @@ public interface ShopProdUnitService extends IService<ShopProdUnit> {
* 新增商品单位
*
* @param dto 商品单位数据
* @return 新增商品单位ID
*/
void addShopProdUnit(ShopProdUnitDTO dto);
Long addShopProdUnit(ShopProdUnitDTO dto);
/**
* 更新商品单位

View File

@@ -0,0 +1,88 @@
package com.czg.product.service;
/**
* @author ww
* @description
*/
public interface ShopSyncService {
/**
* 同步数据 将源店铺信息 同步到目标店铺(包括分组 分类 单位 规格 商品 SKU 耗材)
*
* @param sourceShopId 源店铺ID
* @param targetShopId 目标店铺ID
*/
void sync(Long sourceShopId, Long targetShopId, Long sysUserId);
/**
* 同步单位(新增/修改字段/逻辑删除 不包含删除) 将源店铺的单位同步到 开了同步商品开关的子店铺
*
* @param sourceShopId 主店ID
* @param unitId 主店单位Id
*/
void syncUnitBySourceShop(Long sourceShopId, Long unitId, Long sysUserId);
/**
* 同步规格(新增/修改字段/逻辑删除 不包含删除) 将源店铺的规格同步到 开了同步商品开关的子店铺
*
* @param sourceShopId 主店ID
* @param specId 主店规格Id
*/
void syncSpecBySourceShop(Long sourceShopId, Long specId, Long sysUserId);
/**
* 同步分类(新增/修改字段/逻辑删除 不包含删除) 将源店铺的分类同步到 开了同步商品开关的子店铺
*
* @param sourceShopId 主店ID
* @param categoryId 主店分类Id
*/
void syncCategoryBySourceShop(Long sourceShopId, Long categoryId, Long sysUserId);
/**
* 同步商品 会同步Sku新增/修改字段/逻辑删除 不包含删除) 将源店铺的商品同步到 开了同步商品开关的子店铺
*
* @param sourceShopId 主店ID
* @param productId 主店商品Id
*/
void syncProductBySourceShop(Long sourceShopId, Long productId, Long sysUserId);
/**
* 同步分组 (新增/修改字段/逻辑删除 不包含删除) 将源店铺的分组同步到 开了同步商品开关的子店铺
*
* @param sourceShopId 主店ID
* @param groupId 主店分组Id
*/
void syncGroupBySourceShop(Long sourceShopId, Long groupId, Long sysUserId);
/**
* 同步耗材分组 (新增/修改字段/逻辑删除 不包含删除) 将源店铺的耗材分组同步到 开了同步耗材开关的子店铺
*
* @param sourceShopId 主店ID
* @param consGroupId 主店耗材分组Id
*/
void syncConsGroupBySourceShop(Long sourceShopId, Long consGroupId, Long sysUserId);
/**
* 同步耗材信息(新增/修改字段/逻辑删除 不包含删除) 将源店铺的耗材信息同步到 开了同步耗材开关的子店铺
*
* @param sourceShopId 主店ID
* @param consInfoId 主店ID
*/
void syncConsInfoBySourceShop(Long sourceShopId, Long consInfoId, Long sysUserId);
/**
* 同步商品绑定耗材关联关系 开了同步耗材开关的子店铺
*
* @param sourceShopId 主店ID
* @param sourceProdId 主店商品ID
*/
void syncConsProBySourceShop(Long sourceShopId, Long sourceProdId, Long sysUserId);
/**
* 同步供应商 开了同步耗材开关的子店铺
*
* @param sourceShopId 主店ID
* @param vendorId 供应商Id
*/
void syncVendorBySourceShop(Long sourceShopId, Long vendorId, Long sysUserId);
}

View File

@@ -70,7 +70,7 @@ public interface ShopVendorService extends IService<ShopVendor> {
* @param shopId 店铺id
* @return 账单
*/
Page<ShopVendorBillVO> billList(Long shopId);
Page<ShopVendorBillVO> billList(Long shopId, String key);
/**
* 账单记录明细
@@ -79,7 +79,7 @@ public interface ShopVendorService extends IService<ShopVendor> {
* @param vendorId 供应商id
* @return 分页
*/
Page<ShopVendorBillRecordVO> billRecord(Long shopId, Integer vendorId);
Page<ShopVendorBillRecordVO> billRecord(Long shopId, Integer vendorId, String key);
/**
* 账单付款

View File

@@ -78,12 +78,13 @@ public interface UProductService extends IService<Product> {
/**
* 分组计算是否在可售时间内
*
* @param prodIsSaleTime 商品是否可售
* @param useTime 开启时间管控 0:否1:是
* @param startTime 起售时间
* @param endTime 停售时间
* @return 是否可售时间 1-是0-否
*/
Integer calcIsSaleTime(Integer useTime, LocalTime startTime, LocalTime endTime);
Integer calcIsSaleTime(int prodIsSaleTime, Integer useTime, LocalTime startTime, LocalTime endTime);
/**
* 商品计算是否在可售时间内

View File

@@ -40,7 +40,7 @@ public class ProductGroupVo implements Serializable {
/**
* 商品ID
*/
private Integer proId;
private Long proId;
/**
* 商品名称
*/
@@ -48,7 +48,7 @@ public class ProductGroupVo implements Serializable {
/**
* skuId
*/
private Integer skuId;
private Long skuId;
/**
* sku名称
*/

View File

@@ -0,0 +1,20 @@
package com.czg.product.vo;
import com.czg.product.entity.ProdSku;
import com.czg.product.entity.Product;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.List;
/**
* @author Administrator
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProductVO extends Product {
private BigDecimal lowPrice;
private List<ProdSku> skuList;
private Integer isSaleTime;
}

View File

@@ -67,11 +67,27 @@ public class ShopProductSkuInfoVo implements Serializable {
*/
private BigDecimal realSalesNumber;
/**
* 是否售罄
* 是否售罄同isSoldStock
*/
private Integer isPauseSale;
/**
* 商品库存
*/
private Integer stockNumber;
/**
* 是否售罄isPauseSale
*/
private Integer isSoldStock;
/**
* 是否上架(同isGrounding)
*/
private Integer isSale;
/**
* 是否开启库存
*/
private Integer isStock;
/**
* 是否上架(同isSale)
*/
private Integer isGrounding;
}

View File

@@ -109,4 +109,12 @@ public class ShopProductVo implements Serializable {
* 销量
*/
private BigDecimal salesVolume;
/**
* 店铺id
*/
private Long shopId;
/**
* 是否开启库存
*/
private Integer isStock;
}

View File

@@ -27,4 +27,8 @@ public interface CacheConstant {
* 点餐机PC端商品列表
*/
String ADMIN_CLIENT_PRODUCT_LIST = ADMIN_CLIENT_PRODUCT_INFO + "list";
/**
* 点餐机PC端商品列表
*/
String SHOP_PRODUCT_STOCK = "shop:{}:product-stock:{}";
}

View File

@@ -73,9 +73,14 @@ public class PageUtil {
*/
public QueryWrapper buildSortQueryWrapper() {
QueryWrapper queryWrapper = QueryWrapper.create();
String orderBy = ServletUtil.getRequest().getParameter(ORDER_BY);
if (StrUtil.isNotEmpty(orderBy)) {
queryWrapper.orderBy(SqlUtil.escapeOrderBySql(orderBy));
try {
HttpServletRequest request = ServletUtil.getRequest();
String orderBy = request.getParameter(ORDER_BY);
if (StrUtil.isNotEmpty(orderBy)) {
queryWrapper.orderBy(SqlUtil.escapeOrderBySql(orderBy));
}
} catch (Exception e) {
//System.out.println("排序参数异常");
}
return queryWrapper;
}

View File

@@ -0,0 +1,22 @@
package com.czg.service.account.mapper;
import com.czg.account.dto.ShopBranchDTO;
import com.czg.account.entity.ShopConfig;
import com.czg.account.param.ShopBranchParam;
import com.mybatisflex.core.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 店铺配置扩展
*
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-04-03
*/
@Mapper
public interface ShopConfigMapper extends BaseMapper<ShopConfig> {
List<ShopBranchDTO> findBranchList(ShopBranchParam param);
}

View File

@@ -0,0 +1,14 @@
package com.czg.service.account.mapper;
import com.mybatisflex.core.BaseMapper;
import com.czg.account.entity.SyncNotice;
/**
* 映射层。
*
* @author zs
* @since 2025-04-07
*/
public interface SyncNoticeMapper extends BaseMapper<SyncNotice> {
}

View File

@@ -16,4 +16,5 @@ public interface SysMenuMapper extends BaseMapper<SysMenu> {
List<SysMenu> selectByUserId(@Param("userId") Long userId, @Param("type") Integer type);
List<SysMenu> selectByRoleId(@Param("roleId") Long roleId);
}

View File

@@ -1,5 +1,6 @@
package com.czg.service.account.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
@@ -12,6 +13,7 @@ import com.czg.account.vo.LoginVO;
import com.czg.config.RedisCst;
import com.czg.enums.PlatformTypeEnum;
import com.czg.enums.StatusEnum;
import com.czg.enums.YesNoEnum;
import com.czg.exception.ApiNotPrintException;
import com.czg.sa.MyStpLogic;
import com.czg.sa.StpKit;
@@ -49,6 +51,8 @@ public class AuthorizationServiceImpl implements AuthorizationService {
@Resource
private SysMenuMapper sysMenuMapper;
@Resource
private ShopBranchService shopBranchService;
@Resource
private HandoverRecordService handoverRecordService;
@@ -140,7 +144,10 @@ public class AuthorizationServiceImpl implements AuthorizationService {
throw new ApiNotPrintException("店铺已到期,请联系区域经理续费");
}
}
boolean isAllowAccountLogin = shopBranchService.isAllowAccountLogin(shopInfo.getId());
if (!isAllowAccountLogin) {
throw new ApiNotPrintException("当前分店账号被禁止登录");
}
StpKit.USER.login(user.getId(), user.getAccount(), shopInfo.getId(), shopInfo.getShopName(), isStaff ? MyStpLogic.LoginType.STAFF : MyStpLogic.LoginType.MANAGER, user.getIsAdmin());
// 查询角色
List<SysRole> roleList = sysRoleService.getByUserId(user.getId());
@@ -148,14 +155,22 @@ public class AuthorizationServiceImpl implements AuthorizationService {
if (user.getIsAdmin()) {
roleNames.add("admin");
}
StpKit.USER.addRoleList(roleNames);
// 权限赋予
List<String> promissionList = sysMenuMapper.selectByUserId(user.getId(), null).stream().map(SysMenu::getPermission).filter(StrUtil::isNotBlank).collect(Collectors.toList());
// 加入员工权限
if (shopStaffPromissionList != null && !shopStaffPromissionList.isEmpty()) {
promissionList.addAll(shopStaffPromissionList);
}
boolean isEnableSync = StpKit.USER.isEnableSync(shopInfo.getId());
if (isEnableSync && CollUtil.contains(roleNames, "商户")) {
roleNames.remove("商户");
roleNames.add("分店商户");
List<String> headShopPromissionList = sysMenuMapper.selectByRoleId(2L).stream().map(SysMenu::getPermission).filter(StrUtil::isNotBlank).toList();
List<String> branchShopPromissionList = sysMenuMapper.selectByRoleId(3L).stream().map(SysMenu::getPermission).filter(StrUtil::isNotBlank).toList();
promissionList.removeAll(headShopPromissionList);
promissionList.addAll(branchShopPromissionList);
}
StpKit.USER.addRoleList(roleNames);
StpKit.USER.addPermissionList(promissionList);
String platformType = ServletUtil.getHeaderIgnoreCase(ServletUtil.getRequest(), "platformType");
if (PlatformTypeEnum.PC_CLIENT.getValue().equals(platformType)) {
@@ -168,6 +183,60 @@ public class AuthorizationServiceImpl implements AuthorizationService {
return new LoginVO(StpKit.USER.getTokenInfo(), new ArrayList<>(), loginDTO.loginType(), shopInfo);
}
@Override
public void switchTo(Long sysUserId) {
Long headId = StpKit.USER.getHeadId();
long shopId = StpKit.USER.getLoginIdAsLong();
ShopInfo currentInfo = shopInfoService.getById(shopId);
if (currentInfo.getIsHeadShop() != YesNoEnum.YES.value() && headId == null) {
throw new ApiNotPrintException("登录账号无权限切换");
}
SysUser sysUser = sysUserService.getById(sysUserId);
if (sysUser == null) {
throw new ApiNotPrintException("用户不存在");
}
ShopInfo shopInfo = shopInfoService.getById(sysUser.getId());
if (shopInfo == null) {
throw new ApiNotPrintException("店铺信息不存在");
}
// 主店铺切换子店铺
if ((headId == null && !shopInfo.getMainId().equals(shopId)) || (!sysUser.getId().equals(headId) && shopInfo.getMainId() == null) ||
(headId != null && !sysUserId.equals(headId) && !shopInfo.getMainId().equals(headId))) {
Long headShopId = StpKit.USER.getHeadShopId();
Long changeHeadShopId = StpKit.USER.getHeadShopId(sysUserId);
if (!changeHeadShopId.equals(headShopId)) {
throw new ApiNotPrintException("目标店铺非登录账号所有");
}
}
// 查询角色
List<SysRole> roleList = sysRoleService.getByUserId(sysUser.getId());
List<String> roleNames = roleList.stream().map(SysRole::getName).collect(Collectors.toList());
if (sysUser.getIsAdmin()) {
roleNames.add("admin");
}
// 权限赋予
List<String> promissionList = sysMenuMapper.selectByUserId(sysUser.getId(), null).stream().map(SysMenu::getPermission).filter(StrUtil::isNotBlank).toList();
List<String> newPromissionList = new ArrayList<>(promissionList);
boolean isEnableSync = StpKit.USER.isEnableSync(shopInfo.getId());
if (isEnableSync && CollUtil.contains(roleNames, "商户")) {
roleNames.remove("商户");
roleNames.add("分店商户");
List<String> headShopPromissionList = sysMenuMapper.selectByRoleId(2L).stream().map(SysMenu::getPermission).filter(StrUtil::isNotBlank).toList();
List<String> branchShopPromissionList = sysMenuMapper.selectByRoleId(3L).stream().map(SysMenu::getPermission).filter(StrUtil::isNotBlank).toList();
newPromissionList.removeAll(headShopPromissionList);
newPromissionList.addAll(branchShopPromissionList);
}
StpKit.USER.addRoleList(roleNames);
StpKit.USER.switchTo(sysUser.getId().equals(headId), sysUser.getId(), sysUser.getAccount(), shopInfo.getId(), shopInfo.getShopName(), MyStpLogic.LoginType.MANAGER, sysUser.getIsAdmin());
StpKit.USER.addPermissionList(newPromissionList);
StpKit.USER.addRoleList(roleNames);
}
@NotNull
private static HandoverRecord getHandoverRecord(boolean isStaff, ShopInfo shopInfo, ShopStaff shopStaff) {
HandoverRecord entity = new HandoverRecord();

View File

@@ -52,7 +52,7 @@ public class MemberPointsServiceImpl extends ServiceImpl<MemberPointsMapper, Mem
queryWrapper.like(MemberPoints::getPhone, param.getPhone());
}
Long shopId = StpKit.USER.getShopId(0L);
Long shopId = StpKit.USER.getUsableShopId();
queryWrapper.eq(MemberPoints::getShopId, shopId);
queryWrapper.orderBy(MemberPoints::getShopUserId, false);
return queryWrapper;

View File

@@ -1,13 +1,23 @@
package com.czg.service.account.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.account.dto.pad.*;
import com.czg.account.entity.*;
import com.czg.account.entity.PadLayout;
import com.czg.account.entity.PadProductCategory;
import com.czg.account.entity.PadProductCategoryDetail;
import com.czg.account.entity.ShopProdCategory;
import com.czg.account.service.*;
import com.czg.enums.YesNoEnum;
import com.czg.exception.ApiNotPrintException;
import com.czg.product.entity.ProdSku;
import com.czg.product.entity.Product;
import com.czg.product.service.ProdSkuService;
import com.czg.product.service.ProductRpcService;
import com.czg.product.service.ProductService;
import com.czg.product.vo.ProductVO;
import com.czg.service.account.mapper.PadProductCategoryDetailMapper;
import com.czg.utils.JoinQueryWrapper;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@@ -17,8 +27,13 @@ import jakarta.annotation.Resource;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.TextStyle;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* @author Administrator
@@ -31,6 +46,10 @@ public class PadProdServiceImpl implements PadProdService {
private PadProductCategoryService padProductCategoryService;
@DubboReference
private ProductService productService;
@DubboReference
private ProductRpcService productRpcService;
@DubboReference
private ProdSkuService prodSkuService;
@Resource
private ShopProdCategoryService shopProdCategoryService;
@Resource
@@ -44,6 +63,40 @@ public class PadProdServiceImpl implements PadProdService {
return PageUtil.convert(new PageInfo<>(padProductCategoryDetailMapper.selectPageByKeyAndShopId(shopId, productCategoryId)));
}
/**
* 计算是否在可售时间内
*
* @param days 星期几,例如 "Monday,Tuesday"
* @param startTime 起售时间
* @param endTime 停售时间
* @return 是否可售时间 1-是0-否
*/
public Integer calcIsSaleTime(String days, LocalTime startTime, LocalTime endTime) {
if (StrUtil.isBlank(days) || ObjUtil.isNull(startTime) || ObjUtil.isNull(endTime)) {
return YesNoEnum.NO.value();
}
String today = getWeekDayEnName();
List<String> dayList = StrUtil.split(days, ",");
LocalTime now = LocalTime.now().withNano(0);
if (CollUtil.contains(dayList, today) && now.isAfter(startTime) && now.isBefore(endTime)) {
return YesNoEnum.YES.value();
}
return YesNoEnum.NO.value();
}
/**
* 获取当前日期是星期几的英文名称
*
* @return 星期几的英文名称,例如 "Monday" 或 "Friday"
*/
private String getWeekDayEnName() {
// 获取当前日期
LocalDate currentDate = LocalDate.now();
// 获取当前日期是星期几,返回一个 DayOfWeek 枚举类型的实例
DayOfWeek dayOfWeek = currentDate.getDayOfWeek();
return dayOfWeek.getDisplayName(TextStyle.FULL, Locale.ENGLISH);
}
@Override
public PadDetailDTO detail(Long shopId, Long padProductCategory) {
PadProductCategory padCategory = padProductCategoryService.getOne(new QueryWrapper().eq(PadProductCategory::getShopId, shopId).eq(PadProductCategory::getId, padProductCategory));
@@ -57,10 +110,17 @@ public class PadProdServiceImpl implements PadProdService {
List<Long> productIds = padProductCategoryDetailMapper.selectListByQuery(new QueryWrapper().eq(PadProductCategoryDetail::getPadProductCategoryId, padProductCategory)).stream().map(PadProductCategoryDetail::getProductId).toList();
padDetailDTO.setProductIdList(productIds);
if (!productIds.isEmpty()) {
List<Product> products = productService.list(new QueryWrapper().in(Product::getId, productIds).eq(Product::getShopId, shopId));
List<ProductVO> products = productRpcService.listAndLowPrice(shopId, productIds);
products.parallelStream().forEach(item -> {
List<ProdSku> skuList = prodSkuService.list(new QueryWrapper().eq(ProdSku::getProductId, item.getId()));
item.setSkuList(skuList);
item.setIsSaleTime(calcIsSaleTime(item.getDays(), item.getStartTime(), item.getEndTime()));
});
padDetailDTO.setProductList(products);
}
return padDetailDTO;
}

View File

@@ -0,0 +1,197 @@
package com.czg.service.account.service.impl;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjUtil;
import com.czg.account.dto.ShopBranchDTO;
import com.czg.account.entity.ShopConfig;
import com.czg.account.entity.ShopInfo;
import com.czg.account.enums.BranchDataSyncMethodEnum;
import com.czg.account.enums.ShopTypeEnum;
import com.czg.account.param.ShopBranchParam;
import com.czg.account.service.ShopBranchService;
import com.czg.account.service.ShopUserSyncService;
import com.czg.enums.YesNoEnum;
import com.czg.exception.CzgException;
import com.czg.product.service.ShopSyncService;
import com.czg.sa.StpKit;
import com.czg.service.account.mapper.ShopConfigMapper;
import com.czg.service.account.mapper.ShopInfoMapper;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 分店管理Service实现类
*
* @author tankaikai
* @since 2025-04-07 14:20
*/
@Slf4j
@Service
public class ShopBranchServiceImpl implements ShopBranchService {
@Resource
private ShopConfigMapper shopConfigMapper;
@Resource
private ShopInfoMapper shopInfoMapper;
@DubboReference
private ShopSyncService shopSyncService;
@Resource
private ShopUserSyncService shopUserSyncService;
@Override
public Page<ShopBranchDTO> findPage(ShopBranchParam param) {
PageHelper.startPage(PageUtil.buildPageHelp());
List<ShopBranchDTO> branchList = shopConfigMapper.findBranchList(param);
return PageUtil.convert(new PageInfo<>(branchList));
}
@Override
public void settingDataSyncMethod(Long shopId, String dataSyncMethod) {
ShopInfo shopInfo = shopInfoMapper.selectOneById(shopId);
if (shopInfo == null) {
throw new CzgException("店铺不存在");
}
ShopConfig shopConfig = shopConfigMapper.selectOneById(shopInfo.getId());
if (shopConfig == null) {
throw new CzgException("店铺配置信息不存在");
}
if (ShopTypeEnum.ONLY.getValue().equals(shopInfo.getShopType())) {
throw new CzgException("单店不支持设置数据同步方式");
}
if (ObjUtil.defaultIfNull(shopInfo.getIsHeadShop(), 0) == YesNoEnum.NO.value()) {
throw new CzgException("非主店不能设置数据同步方式");
}
boolean contains = BranchDataSyncMethodEnum.checkValue(dataSyncMethod);
if (!contains) {
throw new CzgException("非法的数据同步方式值");
}
shopConfig.setBranchDataSyncMethod(dataSyncMethod);
shopConfigMapper.update(shopConfig);
}
@Override
public void dataSyncEnable(Long branchShopId) {
Long shopId = StpKit.USER.getShopId(0L);
ShopInfo shopInfo = shopInfoMapper.selectOneById(shopId);
if (shopInfo == null) {
throw new CzgException("主店铺不存在");
}
ShopConfig shopConfig = shopConfigMapper.selectOneById(shopInfo.getId());
if (shopConfig == null) {
throw new CzgException("主店铺配置信息不存在");
}
if (ShopTypeEnum.ONLY.getValue().equals(shopInfo.getShopType())) {
throw new CzgException("数据错误:主店铺类型为单店");
}
if (ObjUtil.defaultIfNull(shopInfo.getIsHeadShop(), 0) == YesNoEnum.NO.value()) {
throw new CzgException("数据错误:当前店铺不是主店");
}
ShopInfo branchShop = shopInfoMapper.selectOneByQuery(QueryWrapper.create().eq(ShopInfo::getMainId, shopInfo.getId()).eq(ShopInfo::getId, branchShopId));
if (branchShop == null) {
throw new CzgException("对应的分店信息不存在");
}
if (ShopTypeEnum.ONLY.getValue().equals(branchShop.getShopType())) {
throw new CzgException("数据错误:分店店铺类型错误");
}
ShopConfig branchConfig = shopConfigMapper.selectOneById(branchShop.getId());
branchConfig.setIsEnableProdSync(YesNoEnum.YES.value());
branchConfig.setIsEnableConsSync(YesNoEnum.YES.value());
branchConfig.setIsEnableVipSync(YesNoEnum.YES.value());
shopConfigMapper.update(branchConfig);
long sysUserId = StpKit.USER.getLoginIdAsLong();
ThreadUtil.execAsync(() -> {
ThreadUtil.safeSleep(3000L);
log.info("开始同步店铺id{}分店id{} 操作人Id:{}", shopId, branchShop.getId(), sysUserId);
// 同步商品和耗材
shopSyncService.sync(shopId, branchShop.getId(), sysUserId);
log.info("同步结束店铺id{}分店id{} 操作人Id:{}", shopId, branchShop.getId(), sysUserId);
});
ThreadUtil.execAsync(() -> {
// 同步会员信息
shopUserSyncService.syncMergeShopUser(shopId, branchShop.getId());
});
}
@Override
public void accountEnable(Long branchShopId) {
Long shopId = StpKit.USER.getShopId(0L);
ShopInfo shopInfo = shopInfoMapper.selectOneById(shopId);
if (shopInfo == null) {
throw new CzgException("主店铺不存在");
}
ShopConfig shopConfig = shopConfigMapper.selectOneById(shopInfo.getId());
if (shopConfig == null) {
throw new CzgException("主店铺配置信息不存在");
}
if (ShopTypeEnum.ONLY.getValue().equals(shopInfo.getShopType())) {
throw new CzgException("数据错误:主店铺类型为单店");
}
if (ObjUtil.defaultIfNull(shopInfo.getIsHeadShop(), 0) == YesNoEnum.NO.value()) {
throw new CzgException("数据错误:当前店铺不是主店");
}
ShopInfo branchShop = shopInfoMapper.selectOneByQuery(QueryWrapper.create().eq(ShopInfo::getMainId, shopInfo.getId()).eq(ShopInfo::getId, branchShopId));
if (branchShop == null) {
throw new CzgException("对应的分店信息不存在");
}
if (ShopTypeEnum.ONLY.getValue().equals(branchShop.getShopType())) {
throw new CzgException("数据错误:分店店铺类型错误");
}
ShopConfig branchConfig = shopConfigMapper.selectOneById(branchShop.getId());
branchConfig.setIsAllowAccountLogin(YesNoEnum.YES.value());
shopConfigMapper.update(branchConfig);
}
@Override
public void accountDisable(Long branchShopId) {
Long shopId = StpKit.USER.getShopId(0L);
ShopInfo shopInfo = shopInfoMapper.selectOneById(shopId);
if (shopInfo == null) {
throw new CzgException("主店铺不存在");
}
ShopConfig shopConfig = shopConfigMapper.selectOneById(shopInfo.getId());
if (shopConfig == null) {
throw new CzgException("主店铺配置信息不存在");
}
if (ShopTypeEnum.ONLY.getValue().equals(shopInfo.getShopType())) {
throw new CzgException("数据错误:主店铺类型为单店");
}
if (ObjUtil.defaultIfNull(shopInfo.getIsHeadShop(), 0) == YesNoEnum.NO.value()) {
throw new CzgException("数据错误:当前店铺不是主店");
}
ShopInfo branchShop = shopInfoMapper.selectOneByQuery(QueryWrapper.create().eq(ShopInfo::getMainId, shopInfo.getId()).eq(ShopInfo::getId, branchShopId));
if (branchShop == null) {
throw new CzgException("对应的分店信息不存在");
}
if (ShopTypeEnum.ONLY.getValue().equals(branchShop.getShopType())) {
throw new CzgException("数据错误:分店店铺类型错误");
}
ShopConfig branchConfig = shopConfigMapper.selectOneById(branchShop.getId());
branchConfig.setIsAllowAccountLogin(YesNoEnum.NO.value());
shopConfigMapper.update(branchConfig);
}
@Override
public boolean isAllowAccountLogin(Long branchShopId) {
ShopConfig shopConfig = shopConfigMapper.selectOneById(branchShopId);
if (shopConfig == null) {
return true;
}
if (shopConfig.getMainId() == null) {
return true;
}
if (shopConfig.getIsAllowAccountLogin() == YesNoEnum.YES.value()) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,40 @@
package com.czg.service.account.service.impl;
import com.czg.account.dto.ShopConfigDTO;
import com.czg.account.entity.ShopConfig;
import com.czg.account.service.ShopConfigService;
import com.czg.sa.StpKit;
import com.czg.service.account.mapper.ShopConfigMapper;
import com.czg.service.account.mapper.ShopInfoMapper;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Service;
/**
* 店铺配置扩展
*
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-04-03
*/
@DubboService
public class ShopConfigServiceImpl extends ServiceImpl<ShopConfigMapper, ShopConfig> implements ShopConfigService {
@Resource
private ShopInfoMapper shopInfoMapper;
private QueryWrapper buildQueryWrapper(ShopConfigDTO param) {
QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
/*if (StrUtil.isNotEmpty(param.getName())) {
queryWrapper.like(ShopConfig::getName, param.getName());
}*/
Long shopId = StpKit.USER.getLoginIdAsLong();
queryWrapper.eq(ShopConfig::getMainId, shopId);
queryWrapper.orderBy(ShopConfig::getId, false);
return queryWrapper;
}
}

View File

@@ -7,12 +7,16 @@ import cn.hutool.crypto.SecureUtil;
import com.czg.account.dto.PageDTO;
import com.czg.account.dto.shopinfo.*;
import com.czg.account.entity.*;
import com.czg.account.enums.BranchDataSyncMethodEnum;
import com.czg.account.enums.ShopTypeEnum;
import com.czg.account.service.*;
import com.czg.config.RedisCst;
import com.czg.enums.StatusEnum;
import com.czg.enums.YesNoEnum;
import com.czg.exception.ApiNotPrintException;
import com.czg.exception.CzgException;
import com.czg.resp.CzgResult;
import com.czg.sa.MyStpLogic;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.service.account.mapper.ShopInfoMapper;
@@ -27,6 +31,7 @@ import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.cache.annotation.CacheConfig;
@@ -36,6 +41,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -44,6 +50,7 @@ import java.util.stream.Collectors;
/**
* @author Administrator
*/
@Slf4j
@DubboService
@CacheConfig(cacheNames = "shopInfo")
public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> implements ShopInfoService {
@@ -65,6 +72,8 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
private FreeDineConfigService freeDineConfigService;
@Resource
private PointsBasicSettingService pointsBasicSettingService;
@Resource
private ShopConfigService shopConfigService;
@DubboReference
private SysParamsService sysParamsService;
@@ -72,7 +81,10 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
@Override
@Cacheable(key = "#id")
public ShopInfo getById(Serializable id) {
return super.getById(id);
ShopInfo shopInfo = super.getById(id);
ShopConfig shopConfig = shopConfigService.getById(shopInfo.getId());
BeanUtil.copyProperties(shopConfig, shopInfo);
return shopInfo;
}
private ShopInfo getShopInfo(Long shopId) {
@@ -94,7 +106,7 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
}
@Override
public Page<ShopInfo> get(PageDTO pageDTO, String shopName, Integer status) {
public Page<ShopInfo> get(PageDTO pageDTO, String shopName, Integer status, Integer isHeadShop) {
QueryWrapper queryWrapper = new QueryWrapper();
if (StrUtil.isNotBlank(shopName)) {
queryWrapper.like(ShopInfo::getShopName, shopName);
@@ -102,8 +114,19 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
if (status != null) {
queryWrapper.eq(ShopInfo::getStatus, status);
}
if (isHeadShop != null) {
queryWrapper.eq(ShopInfo::getIsHeadShop, isHeadShop);
}
List<ShopInfo> shopAllList = getMapper().selectListByQuery(query().select(ShopInfo::getId, ShopInfo::getShopName));
Map<Long, String> shopKv = shopAllList.stream().collect(Collectors.toMap(ShopInfo::getId, ShopInfo::getShopName));
queryWrapper.orderBy(ShopInfo::getCreateTime, false);
return page(new Page<>(pageDTO.page(), pageDTO.size()), queryWrapper);
Page<ShopInfo> page = page(new Page<>(pageDTO.page(), pageDTO.size()), queryWrapper);
page.getRecords().forEach(shopInfo -> {
ShopConfig shopConfig = shopConfigService.getById(shopInfo.getId());
BeanUtil.copyProperties(shopConfig, shopInfo);
shopInfo.setHeadShopName(shopKv.get(shopInfo.getMainId()));
});
return page;
}
private void activateShop(ShopInfo shopInfo, String activateCode) {
@@ -116,7 +139,7 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
// 续期
if (shopInfo.getExpireTime() != null && shopInfo.getExpireTime().isAfter(LocalDateTime.now())) {
shopInfo.setExpireTime(DateUtil.offsetMonth(DateUtil.date(shopInfo.getExpireTime()), merchantRegister.getPeriodMonth()).toLocalDateTime());
}else {
} else {
shopInfo.setExpireTime(DateUtil.offsetMonth(DateUtil.date(), merchantRegister.getPeriodMonth()).toLocalDateTime());
}
merchantRegister.setStatus(1);
@@ -127,6 +150,23 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean add(ShopInfoAddDTO shopInfoAddDTO) {
// 如果店铺类型是单店,是否主店要设为否
if (ShopTypeEnum.ONLY.getValue().equals(shopInfoAddDTO.getShopType())) {
shopInfoAddDTO.setIsHeadShop(YesNoEnum.NO.value());
if (shopInfoAddDTO.getMainId() != null) {
throw new CzgException("单店不允许设置主店ID");
}
} else {
if (shopInfoAddDTO.getIsHeadShop() == null) {
throw new CzgException("加盟店/连锁店请选择是否主店");
}
if (shopInfoAddDTO.getIsHeadShop() == YesNoEnum.NO.value() && shopInfoAddDTO.getMainId() == null) {
throw new CzgException("请选择一个店铺做为主店");
}
if (shopInfoAddDTO.getIsHeadShop() == YesNoEnum.YES.value()) {
shopInfoAddDTO.setMainId(null);
}
}
shopInfoAddDTO.setPhone(shopInfoAddDTO.getPhone().trim());
if (StrUtil.isBlank(shopInfoAddDTO.getPhone())) {
throw new ApiNotPrintException("请输入手机号");
@@ -156,7 +196,50 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
// 初始化积分霸王餐设置
freeDineConfigService.getConfig(shopInfo.getId());
pointsBasicSettingService.initInfo(shopInfo.getId());
return updateById(shopInfo);
updateById(shopInfo);
syncSaveConfig(shopInfo, shopInfoAddDTO);
return true;
}
/**
* 同步创建配置信息
*
* @param shopInfo 店铺信息实体
* @param dto 新增店铺信息DTO
*/
private void syncSaveConfig(ShopInfo shopInfo, ShopInfoAddDTO dto) {
ShopConfig shopConfig = new ShopConfig();
shopConfig.setId(shopInfo.getId());
shopConfig.setMainId(shopInfo.getMainId());
shopConfig.setIsEnableProdSync(0);
shopConfig.setIsEnableVipSync(0);
shopConfig.setIsEnableConsSync(0);
shopConfig.setIsAllowAccountLogin(1);
shopConfig.setRemark(null);
shopConfig.setIsCustomAmount(0);
shopConfig.setIsReturnPwd(0);
shopConfig.setIsMemberInPwd(0);
shopConfig.setIsMemberReturnPwd(0);
shopConfig.setIsTableFee(1);
shopConfig.setIsMemberPrice(0);
shopConfig.setIsAccountPay(0);
shopConfig.setBranchDataSyncMethod(null);
if (dto.getIsHeadShop() == YesNoEnum.YES.value()) {
shopConfig.setBranchDataSyncMethod(BranchDataSyncMethodEnum.AUTO.getValue());
}
shopConfigService.save(shopConfig);
}
/**
* 同步修改配置信息
*
* @param shopInfo 店铺信息实体
* @param dto 新增店铺信息DTO
*/
private void syncUpdateConfig(ShopInfo shopInfo, ShopInfoEditDTO dto) {
ShopConfig shopConfig = shopConfigService.getById(shopInfo.getId());
BeanUtil.copyProperties(dto, shopConfig);
shopConfigService.updateById(shopConfig);
}
@Override
@@ -164,19 +247,40 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
public Boolean edit(ShopInfoEditDTO shopInfoEditDTO) {
ShopInfo shopInfo;
if (!StpKit.USER.isAdmin()) {
shopInfo = queryChain().eq(ShopInfo::getId, StpKit.USER.getLoginIdAsLong()).one();
}else {
shopInfo = getById(StpKit.USER.getLoginIdAsLong());
shopInfo = queryChain().eq(ShopInfo::getId, StpKit.USER.getShopId()).one();
} else {
shopInfo = getById(shopInfoEditDTO.getId());
}
if (shopInfo == null) {
throw new CzgException("店铺不存在");
}
BeanUtil.copyProperties(shopInfoEditDTO, shopInfo);
String shopType = shopInfo.getShopType();
Long mainId = shopInfo.getMainId();
Integer isHeadShop = shopInfo.getIsHeadShop();
if (StrUtil.isEmpty(shopInfoEditDTO.getShopType()) || shopType.equals(shopInfoEditDTO.getShopType())) {
// 原来是单店,现在不是单店,那么就允许修改,否则不允许修改
} else if (ShopTypeEnum.ONLY.getValue().equals(shopType) && !ShopTypeEnum.ONLY.getValue().equals(shopInfoEditDTO.getShopType())) {
if (shopInfoEditDTO.getIsHeadShop() == null) {
throw new CzgException("加盟店/连锁店请选择是否主店");
}
if (shopInfoEditDTO.getIsHeadShop() == YesNoEnum.NO.value() && shopInfoEditDTO.getMainId() == null) {
throw new CzgException("请选择一个店铺做为主店");
}
if (shopInfoEditDTO.getIsHeadShop() == YesNoEnum.YES.value()) {
if (mainId != null) {
throw new CzgException("数据错误:当前店铺是非主店,不允许随意切换为主店");
}
}
if (isHeadShop == YesNoEnum.YES.value() && shopInfoEditDTO.getIsHeadShop() == YesNoEnum.NO.value()) {
throw new CzgException("数据错误:当前店铺是主店,不允许随意切换为非主店");
}
} else {
throw new CzgException("禁止连锁店/加盟店修改为单店");
}
if (shopInfoEditDTO.getActivateCode() != null) {
activateShop(shopInfo, shopInfoEditDTO.getActivateCode());
}
BeanUtil.copyProperties(shopInfoEditDTO, shopInfo);
if (shopInfoEditDTO.getOperationPwd() != null) {
String key = "%s%s:%s".formatted(RedisCst.SMS_CODE, shopInfo.getPhone(), "editShopInfoOpePwd");
Object val = redisService.get(key);
@@ -188,6 +292,7 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
redisService.del(key);
}
if (updateById(shopInfo)) {
syncUpdateConfig(shopInfo, shopInfoEditDTO);
SysUser sysUser = sysUserService.getById(shopInfo.getId());
boolean flag = false;
if (!sysUser.getNickName().equals(shopInfo.getShopName())) {
@@ -218,12 +323,16 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
if (!StpKit.USER.isAdmin() && !Objects.equals(StpKit.USER.getShopId(), shopInfo.getId())) {
throw new ApiNotPrintException("店铺信息不存在");
}
ShopConfig shopConfig = shopConfigService.getById(shopInfo.getId());
if (shopConfig == null) {
throw new CzgException("店铺配置不存在");
}
ShopDetailDTO shopDetailDTO = BeanUtil.copyProperties(shopInfo, ShopDetailDTO.class);
SysUser sysUser = sysUserService.getById(shopInfo.getId());
shopDetailDTO.setAccount(sysUser.getAccount());
CzgResult<SysParamsDTO> shopOrderPayBaseUrl = sysParamsService.getParamsByCode("shop_order_pay_base_url");
shopDetailDTO.setPaymentQrcode(shopOrderPayBaseUrl.getData().getParamValue() + "?shopId=" + id);
BeanUtil.copyProperties(shopConfig, shopDetailDTO);
return shopDetailDTO;
}
@@ -238,7 +347,6 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
throw new ApiNotPrintException("台桌状态不可用");
}
ShopInfo shopInfo = getShopInfo(shopTable.getShopId());
double distance = 0;
if (StrUtil.isAllNotBlank(lat, lng, shopInfo.getLat(), shopInfo.getLng())) {
// 计算距离,单位:米
@@ -264,4 +372,26 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
PageHelper.startPage(PageUtil.buildPageHelp());
return PageUtil.convert(new PageInfo<>(mapper.getSubList(lng, lat, distance)));
}
@Override
public List<ShopBranchSelectDTO> findShopBranch(Long shopId) {
List<ShopBranchSelectDTO> list = new ArrayList<>();
ShopInfo shopInfo = mapper.selectOneById(shopId);
ShopBranchSelectDTO head = new ShopBranchSelectDTO();
head.setShopId(shopInfo.getId());
head.setShopName(shopInfo.getShopName());
list.add(head);
MyStpLogic.LoginType loginType = (MyStpLogic.LoginType) StpKit.USER.getSession().get("loginType");
if(loginType.compareTo(MyStpLogic.LoginType.STAFF) == 0){
return list;
}
List<ShopInfo> branchList = mapper.selectListByQuery(query().select(ShopInfo::getId, ShopInfo::getShopName).eq(ShopInfo::getMainId, shopId).orderBy(ShopInfo::getId, true));
for (ShopInfo info : branchList) {
ShopBranchSelectDTO branch = new ShopBranchSelectDTO();
branch.setShopId(info.getId());
branch.setShopName(info.getShopName());
list.add(branch);
}
return list;
}
}

View File

@@ -9,6 +9,7 @@ import com.czg.account.entity.*;
import com.czg.account.service.*;
import com.czg.config.RedisCst;
import com.czg.enums.ShopUserFlowBizEnum;
import com.czg.enums.YesNoEnum;
import com.czg.exception.ApiNotPrintException;
import com.czg.order.entity.OrderInfo;
import com.czg.order.service.OrderDetailService;
@@ -16,6 +17,7 @@ import com.czg.order.service.OrderInfoService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.service.account.mapper.ShopConfigMapper;
import com.czg.service.account.mapper.ShopInfoMapper;
import com.czg.service.account.mapper.ShopUserMapper;
import com.czg.system.entity.SysParams;
@@ -67,6 +69,8 @@ public class ShopUserServiceImpl extends ServiceImpl<ShopUserMapper, ShopUser> i
private ShopExtendService shopExtendService;
@Resource
private FreeDineConfigService freeDineConfigService;
@Resource
private ShopConfigMapper shopConfigMapper;
private ShopUser getUserInfo(Long shopId, Long shopUserId) {
ShopUser shopUser = queryChain().eq(ShopUser::getShopId, shopId).eq(ShopUser::getId, shopUserId).one();
@@ -79,8 +83,9 @@ public class ShopUserServiceImpl extends ServiceImpl<ShopUserMapper, ShopUser> i
@Override
public Page<ShopUserDTO> getPage(String key, Integer isVip, BigDecimal amount) {
Long shopId = StpKit.USER.getUsableShopId();
PageHelper.startPage(PageUtil.buildPageHelp());
return PageUtil.convert(new PageInfo<>(mapper.selectPageByKeyAndIsVip(StpKit.USER.getShopId(), isVip, key, amount)));
return PageUtil.convert(new PageInfo<>(mapper.selectPageByKeyAndIsVip(shopId, isVip, key, amount)));
}
@Override
@@ -148,6 +153,10 @@ public class ShopUserServiceImpl extends ServiceImpl<ShopUserMapper, ShopUser> i
@Override
public ShopUser getShopUserInfo(Long shopId, long userId) {
ShopConfig shopConfig = shopConfigMapper.selectOneById(shopId);
if (shopConfig != null && shopConfig.getIsEnableVipSync() == YesNoEnum.YES.value() && shopConfig.getMainId() != null) {
shopId = shopConfig.getMainId();
}
ShopUser shopUser = queryChain().eq(ShopUser::getShopId, shopId).eq(ShopUser::getUserId, userId).one();
if (shopUser == null) {
shopUser = new ShopUser();
@@ -185,6 +194,10 @@ public class ShopUserServiceImpl extends ServiceImpl<ShopUserMapper, ShopUser> i
@Override
public CzgResult<String> getCode(long userInfoId, long shopId) {
ShopConfig shopConfig = shopConfigMapper.selectOneById(shopId);
if (shopConfig != null && shopConfig.getIsEnableVipSync() == YesNoEnum.YES.value() && shopConfig.getMainId() != null) {
shopId = shopConfig.getMainId();
}
ShopUser shopUser = queryChain().eq(ShopUser::getShopId, shopId).eq(ShopUser::getUserId, userInfoId).one();
AssertUtil.isNull(shopUser, "会员信息不存在");
if (shopUser.getIsVip().equals(0)) {
@@ -300,6 +313,10 @@ public class ShopUserServiceImpl extends ServiceImpl<ShopUserMapper, ShopUser> i
@Override
public ShopUserDetailDTO getInfo(Long shopId, long userId) {
ShopConfig shopConfig = shopConfigMapper.selectOneById(shopId);
if (shopConfig != null && shopConfig.getIsEnableVipSync() == YesNoEnum.YES.value() && shopConfig.getMainId() != null) {
shopId = shopConfig.getMainId();
}
ShopUser shopUser = getOne(new QueryWrapper().eq(ShopUser::getShopId, shopId).eq(ShopUser::getUserId, userId));
UserInfo userInfo = userInfoService.getById(userId);
if (userInfo == null) {
@@ -336,11 +353,11 @@ public class ShopUserServiceImpl extends ServiceImpl<ShopUserMapper, ShopUser> i
@Override
public ShopUser getDetail(Integer id, Integer userId) {
ShopUser shopUser = getOne(new QueryWrapper().eq(ShopUser::getShopId, StpKit.USER.getShopId()).eq(ShopUser::getId, id).eq(ShopUser::getUserId, userId));
ShopUser shopUser = getOne(new QueryWrapper().eq(ShopUser::getShopId, StpKit.USER.getUsableShopId()).eq(ShopUser::getId, id).eq(ShopUser::getUserId, userId));
long count = shopActivateCouponRecordService.count(new QueryWrapper().eq(ShopActivateCouponRecord::getShopUserId, shopUser.getId()).eq(ShopActivateCouponRecord::getStatus, 0));
ShopUserDTO shopUserDTO = BeanUtil.copyProperties(shopUser, ShopUserDTO.class);
shopUserDTO.setCouponNum(count);
shopUserDTO.setOrderNumber(orderInfoService.count(new QueryWrapper().eq(OrderInfo::getUserId, userId).eq(OrderInfo::getShopId, shopUser.getShopId()).eq(OrderInfo::getStatus, "done")));
shopUserDTO.setOrderNumber(orderInfoService.count(new QueryWrapper().eq(OrderInfo::getUserId, userId).eq(OrderInfo::getShopId, StpKit.USER.getShopId(0L)).eq(OrderInfo::getStatus, "done")));
return shopUserDTO;
}
}

View File

@@ -0,0 +1,170 @@
package com.czg.service.account.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.czg.account.entity.ShopUser;
import com.czg.account.entity.ShopUserFlow;
import com.czg.account.service.ShopUserSyncService;
import com.czg.service.account.mapper.ShopUserMapper;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 店铺用户同步Service实现类
*
* @author tankaikai
* @since 2025-04-08 10:18
*/
@Service
public class ShopUserSyncServiceImpl implements ShopUserSyncService {
@Resource
private ShopUserMapper shopUserMapper;
/**
* 同步合并主分店会员信息
*
* @param headShopId 主店id
* @param branchShopId 分店id
*/
@Override
public synchronized void syncMergeShopUser(Long headShopId, Long branchShopId) {
// 合并前置逻辑:查询主店、分店手机号码不为空的会员信息,分店和主店手机号码进行匹配
// 合并逻辑0分店没有绑定手机号的会员把shop_id改为主店shop_id把分店会员信息jsonArray格式化存储至主店用户信息的merged_users字段中
// 合并逻辑1主店、分店一致如果手机号码一致则把分店会员信息中的 积分、余额、消费金额、消费次数合并到主店会员信息中把分店会员信息jsonArray格式化存储至主店用户信息的merged_users字段中再把分店用户信息删除
// 合并逻辑2主店有、分店没有不用采取任何操作使用主店的会员信息
// 合并逻辑3主店没有、分店有把shop_id改为主店shop_id把分店会员信息jsonArray格式化存储至merged_users字段中
// 合并逻辑4当用户补充了手机号码或则修改了手机号码则需要按照手机号码进行会员信息合并把逻辑123重新执行一遍
List<ShopUser> branchShopNotPhoneUserList = shopUserMapper.selectListByQuery(QueryWrapper.create().eq(ShopUser::getShopId, branchShopId)
.and(q -> {
q.isNull(ShopUser::getPhone).or(q1 -> {
q1.eq(ShopUser::getPhone, "");
});
}));
// 分店没有绑定手机号的会员
for (ShopUser shopUser : branchShopNotPhoneUserList) {
Long historyShopId = shopUser.getShopId();
Long historyUserId = shopUser.getUserId();
JSONObject branch = JSONObject.from(shopUser, JSONWriter.Feature.WriteMapNullValue);
JSONArray objects = new JSONArray();
objects.add(branch);
shopUser.setShopId(headShopId);
shopUser.setMergedUsers(objects.toJSONString(JSONWriter.Feature.WriteMapNullValue));
shopUserMapper.update(shopUser);
// 更新会员流水记录到主店
UpdateChain.of(ShopUserFlow.class)
.set(ShopUserFlow::getShopId, headShopId)
.eq(ShopUserFlow::getShopId, historyShopId)
.eq(ShopUserFlow::getUserId, historyUserId)
.update();
}
List<ShopUser> headShopUserList = shopUserMapper.selectListByQuery(QueryWrapper.create().eq(ShopUser::getShopId, headShopId).isNotNull(ShopUser::getPhone));
List<ShopUser> branchShopUserList = shopUserMapper.selectListByQuery(QueryWrapper.create().eq(ShopUser::getShopId, branchShopId).isNotNull(ShopUser::getPhone));
// 如果分店没有符合条件的会员,则不进行合并
if (CollUtil.isEmpty(branchShopUserList)) {
return;
}
Map<String, ShopUser> headShopUserKv = headShopUserList.stream().collect(Collectors.toMap(ShopUser::getPhone, shopUser -> shopUser));
Map<String, ShopUser> branchShopUserKv = branchShopUserList.stream().collect(Collectors.toMap(ShopUser::getPhone, shopUser -> shopUser));
Set<String> headShopPhoneList = headShopUserList.stream().map(ShopUser::getPhone).collect(Collectors.toSet());
Set<String> branchShopPhoneList = branchShopUserList.stream().map(ShopUser::getPhone).collect(Collectors.toSet());
Set<String> phoneSet = new HashSet<>();
phoneSet.addAll(headShopPhoneList);
phoneSet.addAll(branchShopPhoneList);
// 执行合并逻辑
for (String phone : phoneSet) {
ShopUser headShopUser = headShopUserKv.get(phone);
ShopUser branchShopUser = branchShopUserKv.get(phone);
// 1.如果都有
if (ObjUtil.isNotNull(headShopUser) && ObjUtil.isNotNull(branchShopUser)) {
toMergeCase1(headShopUser, branchShopUser);
// 2.如果主店有,分店没有
} else if (ObjUtil.isNotNull(headShopUser) && ObjUtil.isNull(branchShopUser)) {
toMergeCase2(headShopUser, branchShopId);
// 3.如果主店没有,分店有
} else if (ObjUtil.isNull(headShopUser) && ObjUtil.isNotNull(branchShopUser)) {
toMergeCase3(headShopId, branchShopUser);
}
}
}
/**
* 合并会员信息 1.如果都有
*
* @param headShopUser 主店会员
* @param branchShopUser 分店会员
*/
public void toMergeCase1(ShopUser headShopUser, ShopUser branchShopUser) {
// 合并逻辑1主店、分店一致如果手机号码一致则把分店会员信息中的 积分、余额、消费金额、消费次数合并到主店会员信息中把分店会员信息jsonArray格式化存储至主店用户信息的merged_users字段中再把分店用户信息删除
headShopUser.setAccountPoints(NumberUtil.nullToZero(headShopUser.getAccountPoints()) + (NumberUtil.nullToZero(branchShopUser.getAccountPoints())));
headShopUser.setAmount(NumberUtil.nullToZero(headShopUser.getAmount()).add(NumberUtil.nullToZero(branchShopUser.getAmount())));
headShopUser.setConsumeCount(NumberUtil.nullToZero(headShopUser.getConsumeCount()) + (NumberUtil.nullToZero(branchShopUser.getConsumeCount())));
headShopUser.setConsumeAmount(NumberUtil.nullToZero(headShopUser.getConsumeAmount()).add(NumberUtil.nullToZero(branchShopUser.getConsumeAmount())));
headShopUser.setUpdateTime(LocalDateTime.now());
String mergedUsers = StrUtil.emptyToDefault(headShopUser.getMergedUsers(), "[]");
JSONArray objects = JSON.parseArray(mergedUsers);
objects.add(JSONObject.from(branchShopUser, JSONWriter.Feature.WriteMapNullValue));
headShopUser.setMergedUsers(JSON.toJSONString(objects, JSONWriter.Feature.WriteMapNullValue));
shopUserMapper.update(headShopUser);
// 更新会员流水记录到主店
UpdateChain.of(ShopUserFlow.class)
.set(ShopUserFlow::getShopId, headShopUser.getShopId())
.eq(ShopUserFlow::getShopId, branchShopUser.getShopId())
.eq(ShopUserFlow::getUserId, branchShopUser.getUserId())
.update();
shopUserMapper.delete(branchShopUser);
}
/**
* 合并会员信息 2.如果主店有,分店没有
*
* @param headShopUser 主店会员
* @param branchShopId 分店id
*/
public void toMergeCase2(ShopUser headShopUser, Long branchShopId) {
// 合并逻辑2主店有、分店没有不用采取任何操作使用主店的会员信息
}
/**
* 合并会员信息 3.如果主店没有,分店有
*
* @param headShopId 主店id
* @param branchShopUser 分店会员信息
*/
public void toMergeCase3(Long headShopId, ShopUser branchShopUser) {
// 合并逻辑3主店没有、分店有把shop_id改为主店shop_id把分店会员信息jsonArray格式化存储至merged_users字段中
Long historyShopId = branchShopUser.getShopId();
Long historyUserId = branchShopUser.getUserId();
JSONObject branch = JSONObject.from(branchShopUser, JSONWriter.Feature.WriteMapNullValue);
JSONArray objects = new JSONArray();
objects.add(branch);
branchShopUser.setShopId(headShopId);
branchShopUser.setMergedUsers(objects.toJSONString(JSONWriter.Feature.WriteMapNullValue));
shopUserMapper.update(branchShopUser);
// 更新会员流水记录到主店
UpdateChain.of(ShopUserFlow.class)
.set(ShopUserFlow::getShopId, headShopId)
.eq(ShopUserFlow::getShopId, historyShopId)
.eq(ShopUserFlow::getUserId, historyUserId)
.update();
}
}

View File

@@ -0,0 +1,98 @@
package com.czg.service.account.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.product.dto.SyncNoticeReadDTO;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.czg.account.entity.SyncNotice;
import com.czg.account.service.SyncNoticeService;
import com.czg.service.account.mapper.SyncNoticeMapper;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 服务层实现。
*
* @author zs
* @since 2025-04-07
*/
@DubboService
public class SyncNoticeServiceImpl extends ServiceImpl<SyncNoticeMapper, SyncNotice> implements SyncNoticeService {
@Override
public void addNotice(Long shopId, Long sysUserId, String name, Long id, Integer type) {
SyncNotice syncNotice = new SyncNotice();
syncNotice.setShopId(shopId);
syncNotice.setSysUserId(sysUserId);
String content = switch (type) {
case 0 -> "新增商品";
case 1 -> "修改商品";
case 2 -> "新增耗材";
case 3 -> "修改耗材";
default -> "";
};
String json = switch (type) {
case 0, 1, 2, 3 -> StrUtil.format("{\"id\":{},\"name\":\"{}\"}", id, name);
default -> "";
};
content = StrUtil.format("{}: {}, 请及时确认;", content, name);
syncNotice.setContent(content);
syncNotice.setExtraJson(json);
save(syncNotice);
}
@Override
public void addNotice(Long shopId, Long sysUserId, String title, String content, String extraJson) {
SyncNotice syncNotice = new SyncNotice();
syncNotice.setShopId(shopId);
syncNotice.setSysUserId(sysUserId);
syncNotice.setTitle(title);
syncNotice.setContent(content);
// syncNotice.setType(type);
// syncNotice.setExtraJson(extraJson);
save(syncNotice);
}
@Override
public Page<SyncNotice> pageInfo(Long shopId, String name, String startTime, String endTime, String title, Integer isRead) {
QueryWrapper queryWrapper = new QueryWrapper().eq(SyncNotice::getShopId, shopId);
if (StrUtil.isNotBlank(name)) {
queryWrapper.like(SyncNotice::getContent, name);
}
if (StrUtil.isNotBlank(startTime)) {
queryWrapper.ge(SyncNotice::getCreateTime, startTime);
}
if (StrUtil.isNotBlank(endTime)) {
queryWrapper.le(SyncNotice::getCreateTime, endTime);
}
queryWrapper.eq(SyncNotice::getTitle, title);
queryWrapper.eq(SyncNotice::getIsRead, isRead);
queryWrapper.orderBy(SyncNotice::getCreateTime, false);
return page(PageUtil.buildPage(), queryWrapper);
}
@Override
public Boolean read(Long shopId, SyncNoticeReadDTO syncNoticeReadDTO) {
if (syncNoticeReadDTO.getNoticeIdList() == null || syncNoticeReadDTO.getNoticeIdList().isEmpty()) {
return updateChain().eq(SyncNotice::getShopId, shopId).set(SyncNotice::getIsRead, 1).set(SyncNotice::getReadTime, DateUtil.date().toLocalDateTime()).update();
}
List<SyncNotice> listed = list(new QueryWrapper().eq(SyncNotice::getShopId, shopId).in(SyncNotice::getId, syncNoticeReadDTO.getNoticeIdList()));
listed.forEach(item -> {
if (item.getIsRead() == 0) {
item.setIsRead(1);
item.setReadTime(DateUtil.date().toLocalDateTime());
}
});
return updateBatch(listed);
}
}

Some files were not shown because too many files have changed in this diff Show More