51 Commits

Author SHA1 Message Date
ce2136b3cb 额外打印 店铺名称 2026-04-15 18:27:29 +08:00
45fbdd514e 打印 调整 2026-04-15 18:17:41 +08:00
44f896168f 规格 2026-04-14 14:23:13 +08:00
c37b4b3601 商品修改 发送通知 2026-04-14 13:45:43 +08:00
c1c7cbba7b 商品修改 发送通知 2026-04-14 13:44:27 +08:00
85bc610c10 商品库存缓存 无意义 2026-04-14 11:37:46 +08:00
3fd7a74356 源店铺不是主店铺或源店铺是单店 报错问题 2026-04-14 11:19:09 +08:00
b547283358 订单取消 重复退库存问题 2026-04-14 10:11:56 +08:00
5a23f37939 商品 报损 备注 2026-04-13 18:02:06 +08:00
b5b8e7c4a8 叫号打印3 2026-04-13 16:11:17 +08:00
a259855d01 叫号打印1 2026-04-13 16:06:23 +08:00
3041ef94e1 叫号打印 2026-04-13 15:50:41 +08:00
74a49426a6 退菜 重复商品问题 2026-04-13 15:05:51 +08:00
75f2eebf7e 检验库存 2026-04-13 10:36:24 +08:00
ca83a3a8a2 关联耗材 2026-04-11 16:35:14 +08:00
6447e4218f 下单时 检验库存数 2026-04-11 10:48:27 +08:00
69cdc8d5cb 商品Id 2026-04-10 17:56:36 +08:00
e789edf637 序列化 2026-04-10 17:10:45 +08:00
48d05dda32 序列化 2026-04-10 17:08:46 +08:00
3fe532ee7d 下单库存校验 2026-04-10 16:57:30 +08:00
0e600d76f8 退款 扣除库存校验 2026-04-10 16:11:43 +08:00
c4b93b6a5b 耗材绑定关系 2026-04-10 15:00:15 +08:00
4948e6e7c8 绑定耗材 商品id不能为空 2026-04-10 14:55:31 +08:00
9fb67730a9 商品Id 2026-04-10 14:49:17 +08:00
ae6caa85a0 商品Id 2026-04-10 14:44:48 +08:00
060d493ebc 小程序 商品 问题 2026-04-10 14:39:35 +08:00
b65080926c 耗材关联问题
小程序 商品 问题
2026-04-10 14:37:22 +08:00
98e11c02aa record问题 2026-04-10 14:13:49 +08:00
3b1fa812db record问题 2026-04-10 14:11:59 +08:00
a0fffc8ccb record问题 2026-04-10 14:09:35 +08:00
b0f0aec94b 商品列表 结构
耗材库存 列表接口
耗材 库存预警值推送更新
cons.info.change.queue
2026-04-10 13:59:52 +08:00
7e698eee0d 耗材联动更新 2026-04-10 10:49:35 +08:00
799167a26b tb_product 新增 refund_mode 2026-04-09 17:30:54 +08:00
86fdcaf8a0 关联关系状态 2026-04-09 17:18:16 +08:00
a1fe1bac16 收音机 / 客户端 商品列表 2026-04-09 17:11:37 +08:00
084baf89b1 收音机 / 客户端 商品列表 2026-04-09 17:01:09 +08:00
3448331b31 收音机 / 客户端 商品列表 2026-04-09 16:54:57 +08:00
caec6b2d0f 额外字段 2026-04-09 16:22:36 +08:00
4116f7cc0d tb_product
删除 库存警戒线 库存开关 库存数量
新增 是否自动售罄 标识
tb_shop_prod_category
新增 refund_mode 退菜是否退库存
tb_shop_config 新增 refund_mode 退菜退库存模式

删除 扣除库存模式
2026-04-09 15:54:14 +08:00
fa33586aae 统计 2026-04-08 15:46:25 +08:00
ff27979337 交班 2026-04-08 13:52:33 +08:00
29681c0ae2 订单总额 2026-04-07 16:32:41 +08:00
be476453a4 格式问题 2026-04-07 16:27:14 +08:00
49a15e33a9 sql错误 2026-04-07 16:16:23 +08:00
2a9a9d0438 退菜数量 2026-04-07 16:13:07 +08:00
65bd5b7ed9 退菜数量 2026-04-07 16:11:51 +08:00
7b948b514a 交班 2026-04-07 16:02:27 +08:00
be37a2d92b 后付费 客看单 2026-04-07 11:40:05 +08:00
bf8be19afd 台桌 区域+名称 2026-04-07 11:07:45 +08:00
06fa5b4f0d 退菜退款标识 2026-04-07 10:46:24 +08:00
3b15bc444b 交班周期 2026-04-03 18:27:52 +08:00
94 changed files with 2916 additions and 3193 deletions

View File

@@ -7,7 +7,6 @@ import com.czg.account.service.HandoverRecordService;
import com.czg.account.vo.HandoverProductListVo;
import com.czg.account.vo.HandoverTotalVo;
import com.czg.annotation.SaAdminCheckPermission;
import com.czg.constants.SystemConstants;
import com.czg.excel.ExcelExportUtil;
import com.czg.log.annotation.OperationLog;
import com.czg.resp.CzgResult;
@@ -38,7 +37,6 @@ public class HandoverRecordController {
* @param endDate 结束时间 格式yyyy-MM-dd
*/
@GetMapping("page")
@OperationLog("交班记录-分页")
@SaAdminCheckPermission(parentName = "交班记录", value = "handoverRecord:page", name = "交班记录-分页")
public CzgResult<Page<HandoverRecordDTO>> page(@RequestParam(required = false) String beginDate, @RequestParam(required = false) String endDate) {
Page<HandoverRecordDTO> page = handoverRecordService.getHandoverRecordPage(beginDate, endDate);
@@ -46,20 +44,33 @@ public class HandoverRecordController {
}
/**
* 交班记录-查看
* 交班记录-详情
*
* @param id 交班记录ID
*/
@GetMapping("/detail/{id}")
@SaAdminCheckPermission(parentName = "交班记录", value = "handoverRecord:detail", name = "交班记录-详情")
public CzgResult<HandoverRecordDTO> detail(@PathVariable Long id) {
HandoverRecord entity = handoverRecordService.getById(id);
HandoverRecordDTO data = BeanUtil.copyProperties(entity, HandoverRecordDTO.class);
return CzgResult.success(data);
}
/**
* 交班记录-商品详情
*
* @param id 交班记录ID
*/
@GetMapping("{id}")
@OperationLog("交班记录-查看")
@SaAdminCheckPermission(parentName = "交班记录", value = "handoverRecord:info", name = "交班记录-查看")
@SaAdminCheckPermission(parentName = "交班记录", value = "handoverRecord:detail", name = "交班记录-详情")
public CzgResult<List<HandoverProductListVo>> info(@PathVariable Long id) {
List<HandoverProductListVo> data = handoverRecordService.getHandoverProductListById(id);
return CzgResult.success(data);
}
/**
* 交班记录-导出
* 交班记录-商品详情导出
*
* @param id 交班记录ID
*/
@@ -71,13 +82,13 @@ public class HandoverRecordController {
ExcelExportUtil.exportToResponse(list, HandoverProductListVo.class, "交班售出商品明细", response);
}
/**
* 收银机-交班数据统计
* 收银机-实时交班数据
*/
@GetMapping("total")
@OperationLog("收银机-交班数据统计")
@SaAdminCheckPermission(parentName = "交班记录", value = "handoverRecord:total", name = "收银机-交班数据统计")
public CzgResult<HandoverTotalVo> total() {
@SaAdminCheckPermission(parentName = "交班记录", value = "handoverRecord:realTime", name = "收银机-实时交班数据")
public CzgResult<HandoverTotalVo> realTime() {
HandoverTotalVo data = handoverRecordService.totalHandoverData();
return CzgResult.success(data);
}
@@ -91,36 +102,8 @@ public class HandoverRecordController {
@OperationLog("收银机-交班/关班")
@SaAdminCheckPermission(parentName = "交班记录", value = "handoverRecord:handover", name = "收银机-交班/关班")
public CzgResult<Long> handover(@RequestParam Integer isPrint) {
Long id = handoverRecordService.handover();
return CzgResult.success(id);
HandoverRecord handoverRecord = handoverRecordService.handover();
handoverRecordService.printHandoverReceipt(handoverRecord, isPrint);
return CzgResult.success(handoverRecord.getId());
}
/**
* 收银机-交班/关班-网络打印机打印交班小票
*
* @param id 交班记录id
*/
@PostMapping("/network/print/{id}")
@OperationLog("收银机-交班/关班-网络打印机打印交班小票")
@SaAdminCheckPermission(parentName = "交班记录", value = "handoverRecord:networkPrint", name = "收银机-交班/关班-网络打印机打印交班小票")
public CzgResult<Void> handover(@PathVariable Long id) {
handoverRecordService.printHandoverReceipt(id, SystemConstants.OneZero.ONE);
return CzgResult.success();
}
/**
* 交班记录-详情
*
* @param id 交班记录ID
*/
@GetMapping("/detail/{id}")
@OperationLog("交班记录-详情")
@SaAdminCheckPermission(parentName = "交班记录", value = "handoverRecord:detail", name = "交班记录-详情")
public CzgResult<HandoverRecordDTO> detail(@PathVariable Long id) {
HandoverRecord entity = handoverRecordService.getById(id);
HandoverRecordDTO data = BeanUtil.copyProperties(entity, HandoverRecordDTO.class);
return CzgResult.success(data);
}
}

View File

@@ -1,11 +1,7 @@
package com.czg.controller.admin;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.czg.account.dto.print.PrinterAddDTO;
import com.czg.account.dto.print.PrinterDelDTO;
import com.czg.account.dto.print.PrinterEditDTO;
import com.czg.account.dto.print.PrinterOrderDTO;
import com.czg.account.entity.PrintMachine;
import com.czg.account.service.PrintMachineService;
import com.czg.annotation.SaAdminCheckPermission;
@@ -48,15 +44,10 @@ public class PrintMachineController {
}
if (StrUtil.isNotBlank(subType)) {
queryWrapper.eq(PrintMachine::getSubType, subType);
queryWrapper.eq(PrintMachine::getPrintType, subType);
}
queryWrapper.orderBy(PrintMachine::getSort, true).orderBy(PrintMachine::getId, false);
Page<PrintMachine> page = printMachineService.page(PageUtil.buildPage(), queryWrapper);
page.getRecords().forEach(item -> {
if (StrUtil.isNotBlank(item.getCategoryIds())) {
item.setCategoryList(JSONArray.parse(item.getCategoryIds()));
}
});
return CzgResult.success(page);
}
@@ -73,15 +64,10 @@ public class PrintMachineController {
}
queryWrapper.in(PrintMachine::getConnectionType, "USB", "局域网");
if (StrUtil.isNotBlank(subType)) {
queryWrapper.eq(PrintMachine::getSubType, subType);
queryWrapper.eq(PrintMachine::getPrintType, subType);
}
queryWrapper.orderBy(PrintMachine::getSort, true).orderBy(PrintMachine::getId, false);
Page<PrintMachine> page = printMachineService.page(PageUtil.buildPage(), queryWrapper);
page.getRecords().forEach(item -> {
if (StrUtil.isNotBlank(item.getCategoryIds())) {
item.setCategoryList(JSONArray.parse(item.getCategoryIds()));
}
});
return CzgResult.success(page);
}
@@ -94,9 +80,6 @@ public class PrintMachineController {
@GetMapping("/detail")
public CzgResult<PrintMachine> detail(@RequestParam Integer id) {
PrintMachine printMachine = printMachineService.getOne(new QueryWrapper().eq(PrintMachine::getId, id).eq(PrintMachine::getShopId, StpKit.USER.getShopId()));
if (printMachine != null && StrUtil.isNotBlank(printMachine.getCategoryIds())) {
printMachine.setCategoryList(JSONArray.parse(printMachine.getCategoryIds()));
}
return CzgResult.success(printMachine);
}
@@ -107,7 +90,7 @@ public class PrintMachineController {
*/
@SaAdminCheckPermission(parentName = "打印机管理", value = "printer:add", name = "打印机新增")
@PostMapping
public CzgResult<Boolean> add(@RequestBody @Validated PrinterAddDTO printerAddDTO) {
public CzgResult<Boolean> add(@RequestBody @Validated PrintMachine printerAddDTO) {
return CzgResult.success(printMachineService.add(StpKit.USER.getShopId(), printerAddDTO));
}
@@ -117,7 +100,7 @@ public class PrintMachineController {
*/
@SaAdminCheckPermission(parentName = "打印机管理", value = "printer:edit", name = "打印机编辑")
@PutMapping
public CzgResult<Boolean> edit(@RequestBody @Validated PrinterEditDTO printerEditDTO) {
public CzgResult<Boolean> edit(@RequestBody @Validated PrintMachine printerEditDTO) {
return CzgResult.success(printMachineService.edit(StpKit.USER.getShopId(), printerEditDTO));
}

View File

@@ -2,7 +2,6 @@ package com.czg.mq;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.czg.config.RabbitConstants;
import com.czg.order.entity.MqLog;
@@ -71,10 +70,10 @@ public class OrderMqListener {
public void orderStockRecover(String orderId) {
long startTime = DateUtil.date().getTime();
log.info("接收到订单取消恢复库存消息:{}", orderId);
MqLog mqLog = new MqLog().setQueue(RabbitConstants.Queue.ORDER_CANCEL_QUEUE).setMsg(orderId).setType("orderStockRecover").setPlat("java.order").setCreateTime(DateUtil.date().toLocalDateTime());
try {
orderInfoRpcService.orderCancelCallback(Long.valueOf(orderId));
} catch (Exception e) {
MqLog mqLog = new MqLog().setQueue(RabbitConstants.Queue.ORDER_CANCEL_QUEUE).setMsg(orderId).setType("orderStockRecover").setPlat("java.order").setCreateTime(DateUtil.date().toLocalDateTime());
log.error("订单取消恢复库存失败", e);
String errorInfo = ExceptionUtil.stacktraceToString(e);
mqLog.setErrInfo(errorInfo);
@@ -88,11 +87,10 @@ public class OrderMqListener {
public void orderStockReturn(String jsonObjStr) {
long startTime = DateUtil.date().getTime();
log.info("接收到订单退款返还库存消息:{}", jsonObjStr);
MqLog mqLog = new MqLog().setQueue(RabbitConstants.Queue.ORDER_REFUND_QUEUE).setMsg(jsonObjStr).setType("orderStockReturn").setPlat("java.order").setCreateTime(DateUtil.date().toLocalDateTime());
try {
JSONObject data = JSON.parseObject(jsonObjStr);
orderInfoRpcService.orderRefundCallback(data);
orderInfoRpcService.orderRefundCallback(JSONObject.parseObject(jsonObjStr));
} catch (Exception e) {
MqLog mqLog = new MqLog().setQueue(RabbitConstants.Queue.ORDER_REFUND_QUEUE).setMsg(jsonObjStr).setType("orderStockReturn").setPlat("java.order").setCreateTime(DateUtil.date().toLocalDateTime());
log.error("订单退款返还库存失败", e);
String errorInfo = ExceptionUtil.stacktraceToString(e);
mqLog.setErrInfo(errorInfo);

View File

@@ -57,29 +57,24 @@ public class PrintMqListener {
if (orderId == null) {
throw new RuntimeException("订单打印失败未传递orderId");
}
//该字段表示 网络打印机是否打印订单 本地传参来的
Boolean printOrder = jsonObject.getBoolean("printOrder");
redisService.runFunAndCheckKey(() -> {
printerHandler.orderHandler(orderId, printOrder != null && !printOrder ? PrinterHandler.PrintTypeEnum.ONE : PrinterHandler.PrintTypeEnum.ONE_AND_ORDER, null);
if (printOrder) {
printerHandler.orderHandler(orderId, PrinterHandler.PrintTypeEnum.ORDER, null);
}
//菜品打印 全是后端
printerHandler.orderHandler(orderId, PrinterHandler.PrintTypeEnum.ONLY_KITCHEN, null);
printerHandler.orderHandler(orderId, PrinterHandler.PrintTypeEnum.ALL_KITCHEN, null);
return null;
}, RedisCst.getLockKey("orderPrint", orderId));
});
}
/**
* 交班打印
*/
@RabbitListener(queues = {"${spring.profiles.active}-" + RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE})
public void handoverPrint(String id) {
invokeFun(RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE, "handoverPrint", "java.order", id, (data) ->
printerHandler.handoverHandler(data));
}
/**
* 叫号打印
*/
@RabbitListener(queues = {"${spring.profiles.active}-" + RabbitConstants.Queue.CALL_TABLE_QUEUE})
public void callTablePrint(String id) {
invokeFun(RabbitConstants.Queue.CALL_TABLE_QUEUE, "callTable", "java.order", id, (data) ->
printerHandler.callHandler(data));
@RabbitListener(queues = {"${spring.profiles.active}-" + RabbitConstants.Queue.OTHER_PRINT_QUEUE})
public void otherPrint(Long shopId, Object o, String printTypeEnum) {
PrinterHandler.PrintTypeEnum typeEnum = PrinterHandler.PrintTypeEnum.valueOf(printTypeEnum);
printerHandler.otherHandler(shopId, o, typeEnum);
}
}

View File

@@ -9,6 +9,7 @@ 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.product.vo.ConsStockRecord;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.utils.AssertUtil;
@@ -44,18 +45,25 @@ public class ConsInfoController {
* 分页
*/
@GetMapping("page")
@OperationLog("耗材信息-分页")
//@SaAdminCheckPermission("consInfo:page")
public CzgResult<Page<ConsInfoDTO>> getConsInfoPage(ConsInfoDTO param) {
Page<ConsInfoDTO> data = consInfoService.getConsInfoPage(param);
return CzgResult.success(data);
}
/**
* 列表
*/
@GetMapping("consStock")
public CzgResult<List<ConsStockRecord>> getConsStockList(Long shopId) {
return CzgResult.success(consInfoService.getConsStockList(shopId));
}
/**
* 列表
*/
@GetMapping("list")
@OperationLog("耗材信息-列表")
//@SaAdminCheckPermission("consInfo:list")
public CzgResult<List<ConsInfoDTO>> getConsInfoList(ConsInfoDTO param) {
List<ConsInfoDTO> data = consInfoService.getConsInfoList(param);
@@ -68,7 +76,6 @@ public class ConsInfoController {
* @param id 耗材信息id
*/
@GetMapping("{id}")
@OperationLog("耗材信息-详情")
//@SaAdminCheckPermission("consInfo:info")
public CzgResult<ConsInfoDTO> getConsInfoById(@PathVariable("id") Long id) {
AssertUtil.isNull(id, "{}不能为空", "id");
@@ -164,21 +171,6 @@ public class ConsInfoController {
return CzgResult.success();
}
/**
* 退款退回开关
*
* @param id 耗材信息id
*/
@PostMapping("onOffIsRefundStock")
@OperationLog("耗材信息-退款退回开关")
//@SaAdminCheckPermission("consInfo:on-off")
public CzgResult<Void> onOffIsRefundStock(@RequestParam Long id, @RequestParam Integer isRefundStockConsInfo) {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
AssertUtil.isNull(isRefundStockConsInfo, "退款退回开关值不能为空");
consInfoService.isRefundStockConsInfo(id, isRefundStockConsInfo);
return CzgResult.success();
}
/**
* 编辑副单位
@@ -200,7 +192,6 @@ public class ConsInfoController {
* 统计
*/
@GetMapping("statistics")
@OperationLog("耗材信息-统计")
//@SaAdminCheckPermission("consInfo:info")
public CzgResult<ConsStatisticsVo> getConsInfoById(ConsInfoParam param) {
Long shopId = StpKit.USER.getShopId(0L);

View File

@@ -16,7 +16,6 @@ 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;
@@ -57,9 +56,6 @@ public class ProductController {
@Resource
private ShopSyncService shopSyncService;
@Resource
private UProductService uProductService;
@Resource
private ShopInfoService shopInfoService;
@@ -72,12 +68,6 @@ public class ProductController {
public CzgResult<Map<String, Object>> getProductPage(ProductDTO param) {
Page<ProductDTO> data = productService.getProductPage(param);
Map<String, Object> map = JSONObject.parseObject(JSONObject.toJSONString(data), Map.class);
if (data.getRecords() != null && !data.getRecords().isEmpty()) {
ProductDTO first = data.getRecords().getFirst();
map.put("warnLine", first.getWarnLine());
} else {
map.put("warnLine", 0);
}
return CzgResult.success(map);
}
@@ -94,14 +84,8 @@ public class ProductController {
*/
@GetMapping("list")
@OperationLog("商品-列表")
//@SaAdminCheckPermission("product:list")
public CzgResult<List<ProductDTO>> getProductList(ProductDTO param) {
Long shopId = StpKit.USER.getShopId();
param.setShopId(shopId);
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);
public CzgResult<List<ProductDTO>> getProductList(@RequestParam(required = false) Long categoryId) {
return CzgResult.success(productService.getProductCacheList(StpKit.USER.getShopId(), categoryId));
}
/**
@@ -135,6 +119,17 @@ public class ProductController {
return CzgResult.success();
}
/**
* 商品-库存变动记录
*/
@GetMapping("stockFlow")
@OperationLog("商品-库存变动记录")
//@SaAdminCheckPermission("consStockFlow:flow")
public CzgResult<Page<ProductStockFlow>> stockFlow(ProductStockFlowParam param) {
Page<ProductStockFlow> data = productService.findProductStockFlowPage(param);
return CzgResult.success(data);
}
/**
* 商品-修改
*/
@@ -150,10 +145,6 @@ public class ProductController {
if (dto.getGroupCategoryId() != null) {
StpKit.USER.checkStaffPermission("yun_xu_xiu_gai_fen_zu");
}
if (dto.getStockNumber() != null) {
StpKit.USER.checkStaffPermission("yun_xu_xiu_gai_shang_pin_ku_cun");
}
Long shopId = StpKit.USER.getShopId();
dto.setShopId(shopId);
productService.updateProduct(dto);
@@ -162,18 +153,6 @@ public class ProductController {
return CzgResult.success();
}
@PostMapping("modifyStock")
@OperationLog("商品-修改库存")
//@SaStaffCheckPermission("yun_xu_xiu_gai_shang_pin")
public CzgResult<Void> updateProductStock(@RequestBody ProductModifyStockParam param) {
ValidatorUtil.validateEntity(param, DefaultGroup.class);
Long shopId = StpKit.USER.getShopId();
param.setShopId(shopId);
productService.updateProductStock(param);
ThreadUtil.execAsync(() -> rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId)));
return CzgResult.success();
}
/**
* 商品-删除
*
@@ -223,6 +202,16 @@ public class ProductController {
return CzgResult.success();
}
/**
* 商品-标记自动售罄
*/
@PostMapping("markIsAutoSoldOut")
public CzgResult<Void> markIsAutoSoldOut(@RequestBody @Validated({DefaultGroup.class}) ProductIsAutoSaleParam param) {
productService.markProductIsAutoSoldOut(StpKit.USER.getShopId(), param);
ThreadUtil.execAsync(() -> rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(StpKit.USER.getShopId())));
return CzgResult.success();
}
/**
* 商品-绑定耗材
*/
@@ -230,13 +219,15 @@ public class ProductController {
@OperationLog("商品-绑定耗材")
//@SaAdminCheckPermission("product:bind")
public CzgResult<Void> bindCons(@RequestBody @Validated({DefaultGroup.class}) ProdConsBindDTO param) {
AssertUtil.isNull(param.getId(), "商品Id不能为空");
prodConsRelationService.saveProdConsRelation(param);
ThreadUtil.execAsync(() -> rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(StpKit.USER.getShopId())));
asyncConsProToShop(param.getId());
return CzgResult.success();
}
/**
* 商品-退款退至库存
* 商品-退款退至库存 开关
*/
@PostMapping("refundToStock")
@OperationLog("商品-退款退至库存")
@@ -247,28 +238,11 @@ public class ProductController {
return CzgResult.success();
}
/**
* 商品-库存预警设置
*/
@PostMapping("stockWarning")
@OperationLog("商品-库存预警设置")
//@SaAdminCheckPermission("product:stockWarning")
public CzgResult<Void> stockWarning(@RequestParam Integer warnLine) {
AssertUtil.isNull(warnLine, "{}不能为空", "warnLine");
if (warnLine < 0) {
throw new CzgException("预警值不能小于0");
}
productService.stockWarning(warnLine);
return CzgResult.success();
}
/**
* 商品-报损
*/
@PostMapping("reportDamage")
@OperationLog("商品-报损")
//@SaStaffCheckPermission("yun_xu_ti_jiao_bao_sun")
//@SaAdminCheckPermission("product:reportDamage")
public CzgResult<Void> reportDamage(@RequestBody ProductReportDamageParam param) {
ValidatorUtil.validateEntity(param, DefaultGroup.class);
productService.reportDamage(param);
@@ -288,17 +262,6 @@ public class ProductController {
return CzgResult.success(data);
}
/**
* 商品-库存变动记录
*/
@GetMapping("stockFlow")
@OperationLog("商品-库存变动记录")
//@SaAdminCheckPermission("consStockFlow:flow")
public CzgResult<Page<ProductStockFlow>> stockFlow(ProductStockFlowParam param) {
Page<ProductStockFlow> data = productService.findProductStockFlowPage(param);
return CzgResult.success(data);
}
/**
* 商品-报损
*/

View File

@@ -2,24 +2,21 @@ package com.czg.controller.user;
import com.czg.constants.SystemConstants;
import com.czg.product.param.ShopProductSkuParam;
import com.czg.product.service.ConsInfoService;
import com.czg.product.service.UProductService;
import com.czg.product.vo.ShopGroupProductVo;
import com.czg.product.vo.ShopProductInfoVo;
import com.czg.product.vo.ShopProductSkuInfoVo;
import com.czg.product.vo.ShopProductVo;
import com.czg.product.vo.*;
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 lombok.AllArgsConstructor;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
/**
@@ -28,11 +25,13 @@ import java.util.Map;
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-02-16
*/
@AllArgsConstructor
@RestController
@RequestMapping("/user/product")
public class UProductController {
private final UProductService uProductService;
@Resource
private UProductService uProductService;
@Resource
private ConsInfoService consInfoService;
/**
* 小程序点餐-热销商品列表
@@ -41,10 +40,9 @@ public class UProductController {
public CzgResult<List<ShopProductVo>> queryHotsProductList() {
Long shopId = StpKit.USER.getShopId(0L);
List<ShopProductVo> list = uProductService.queryHotsProductList(shopId);
list.forEach(prod -> {
prod.setIsSaleTime(uProductService.calcIsSaleTime(prod.getDays(), prod.getStartTime(), prod.getEndTime()));
});
uProductService.refreshProductStock(shopId, list);
// list.forEach(prod -> {
// prod.setIsSaleTime(uProductService.calcIsSaleTime(prod.getDays(), prod.getStartTime(), prod.getEndTime()));
// });
return CzgResult.success(list);
}
@@ -55,9 +53,7 @@ public class UProductController {
public CzgResult<List<ShopGroupProductVo>> queryGroupProductList() {
Long shopId = StpKit.USER.getShopId(0L);
List<ShopGroupProductVo> list = uProductService.queryGroupProductList(shopId);
Map<Long, Integer> productStock = uProductService.findShopProductStock(shopId);
list.forEach(item -> {
uProductService.refreshProductStock(productStock, item.getProductList());
item.getProductList().forEach(prod -> {
prod.setIsSaleTime(uProductService.calcIsSaleTime(prod.getDays(), prod.getStartTime(), prod.getEndTime()));
prod.setIsSaleTime(uProductService.calcIsSaleTime(prod.getIsSaleTime(), item.getUseTime(), item.getSaleStartTime(), item.getSaleEndTime()));
@@ -70,6 +66,14 @@ public class UProductController {
return CzgResult.success(list);
}
/**
* 列表
*/
@GetMapping("consStock")
public CzgResult<List<ConsStockRecord>> getConsStockList(Long shopId) {
return CzgResult.success(consInfoService.getConsStockList(shopId));
}
/**
* 小程序点餐-商品详情
*

View File

@@ -70,26 +70,16 @@ public class RabbitConfig {
return BindingBuilder.bind(orderMachinePrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_MACHINE_PRINT_QUEUE);
}
//------------------------------------------------------交班打票
//------------------------------------------------------其它打印消息打票
@Bean
public Queue handoverPrintQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE, true, false, false);
public Queue otherPrintQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.OTHER_PRINT_QUEUE, true, false, false);
}
@Bean
public Binding bindingHandoverPrintExchange(Queue handoverPrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(handoverPrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE);
}
//------------------------------------------------------叫号 打票
@Bean
public Queue callTablePrintQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.CALL_TABLE_QUEUE, true, false, false);
}
@Bean
public Binding bindingCallTablePrintExchange(Queue callTablePrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(callTablePrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.CALL_TABLE_QUEUE);
public Binding bindingOtherPrintExchange(Queue otherPrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(otherPrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.OTHER_PRINT_QUEUE);
}
//------------------------------------------------------订单取消
@@ -125,6 +115,16 @@ public class RabbitConfig {
public Binding bindingProductInfoChange(Queue productInfoChangeQueue, DirectExchange exchange) {
return BindingBuilder.bind(productInfoChangeQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.PRODUCT_INFO_CHANGE_QUEUE);
}
//------------------------------------------------------ 耗材信息更新
@Bean
public Queue consInfoChangeQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.CONS_INFO_CHANGE_QUEUE, true);
}
@Bean
public Binding bindingConsInfoChange(Queue consInfoChangeQueue, DirectExchange exchange) {
return BindingBuilder.bind(consInfoChangeQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.CONS_INFO_CHANGE_QUEUE);
}
//------------------------------------------------------ 订单退款
@Bean

View File

@@ -14,11 +14,13 @@ public interface RabbitConstants {
public static final String ORDER_STOCK_QUEUE = "order.stock.queue";
public static final String ORDER_REFUND_QUEUE = "order.refund.queue";
public static final String ORDER_CANCEL_QUEUE = "order.cancel.queue";
public static final String ORDER_PRINT_QUEUE = "order.print.queue";
public static final String ORDER_MACHINE_PRINT_QUEUE = "order.machine.print.queue";
public static final String ORDER_HANDOVER_PRINT_QUEUE = "order.handover.print.queue";
public static final String CALL_TABLE_QUEUE = "call.table.print.queue";
public static final String OTHER_PRINT_QUEUE = "other.print.queue";
public static final String PRODUCT_INFO_CHANGE_QUEUE = "product.info.change.queue";
public static final String CONS_INFO_CHANGE_QUEUE = "cons.info.change.queue";
/**
* 订单商品状态队列

View File

@@ -7,6 +7,7 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
@@ -51,38 +52,28 @@ public class RabbitPublisher {
}
/**
* 订单打印消息
* 后付费订单打印消息
*
* @param orderId 订单id
* @param printOrder 是否打印结算单
* @param orderId 订单id
*/
public void sendOrderPrintMsg(String orderId, boolean printOrder, String source) {
log.info("开始发送打印mq消息, orderId: {}, printOrder: {}, source: {}", orderId, printOrder, source);
//厨房票
sendMsg(RabbitConstants.Queue.ORDER_MACHINE_PRINT_QUEUE, new JSONObject().fluentPut("orderId", orderId).fluentPut("printOrder", printOrder).toString());
//前台票
log.info("订单打印消息, orderId: {}, printOrder: {}, source: {}", orderId, printOrder, source);
//结算票 预结算单 客看单
if (printOrder) {
sendMsg(RabbitConstants.Queue.ORDER_PRINT_QUEUE, orderId);
}
}
/**
* 退款订单打印消息
* 厨房票打印消息
*
* @param orderId 订单id
* @param orderId 订单id
* @param printOrder 是否打印结算单
*/
public void sendOrderReturnPrintMsg(String orderId) {
public void sendKitchenOrderPrintMsg(String orderId, boolean printOrder, String source) {
log.info("厨房菜品单打印消息, orderId: {}, printOrder: {}, source: {}", orderId, printOrder, source);
//厨房票
sendMsg(RabbitConstants.Queue.ORDER_MACHINE_PRINT_QUEUE, new JSONObject().fluentPut("orderId", orderId).fluentPut("printOrder", true).toString());
}
/**
* 交班小票打印消息
*
* @param handoverRecordId 交班记录id
*/
public void sendHandoverPrintMsg(String handoverRecordId) {
sendMsg(RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE, handoverRecordId);
sendMsg(RabbitConstants.Queue.ORDER_MACHINE_PRINT_QUEUE, new JSONObject().fluentPut("orderId", orderId).fluentPut("printOrder", printOrder).toString());
}
/**
@@ -95,12 +86,12 @@ public class RabbitPublisher {
}
/**
* 排队叫号小票打印
* 商品信息变动消息
*
* @param id 叫号队列id
* @param shopId 店铺id
*/
public void printCallNumTicket(Long id) {
sendMsg(RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE, id.toString());
public void sendConsInfoChangeMsg(String shopId) {
sendMsg(RabbitConstants.Queue.CONS_INFO_CHANGE_QUEUE, shopId);
}
/**
@@ -155,4 +146,25 @@ public class RabbitPublisher {
rabbitTemplate.convertAndSend(activeProfile + "-" + RabbitConstants.Exchange.CASH_EXCHANGE, activeProfile + "-" + queue, msg);
}
/**
* 其它类型 打印消息
* STOCK 出入库
* DAY_REPORT 经营日报
* PRODUCT_REPORT 商品报表
* RECHARGE 储值单
* STOCK_CHECK 库存盘点
* HANDOVER 交班单
* CALL 排队取号
* @param printType {@link com.czg.service.order.print.PrinterHandler.PrintTypeEnum}
*/
public void sendOtherPrintMsg(Long shopId, Object data, String printType) {
String exchange = activeProfile + "-" + RabbitConstants.Exchange.CASH_EXCHANGE;
String queueName = activeProfile + "-" + RabbitConstants.Queue.OTHER_PRINT_QUEUE;
Map<String, Object> msg = new HashMap<>();
msg.put("shopId", shopId);
msg.put("data", data);
msg.put("printTypeEnum", printType);
rabbitTemplate.convertAndSend(exchange, queueName, msg);
}
}

View File

@@ -3,6 +3,7 @@ package com.czg.config;
/**
*
* key常量
*
* @author Administrator
*/
public interface RedisCst {
@@ -12,7 +13,6 @@ public interface RedisCst {
String SYS_LOG_KEY = "sys:log:";
/**
* key过期监听
*/
@@ -50,11 +50,18 @@ public interface RedisCst {
// 排队取号全局号码
String TABLE_CALL_NUMBER = "table:call:number:";
String PRINT_ORDER_DETAIL = "print:order:detail:";
// 点歌地址url
String SONG_URL = "song:";
class kitchen {
//后厨总单
public static final String ALL = "print:kitchen:all";
//菜品单
public static final String NORMAL = "print:kitchen:normal";
//退菜单
public static final String REFUND_ALL = "print:kitchen:refundAll";
}
static String getLockKey(String sign, Object... args) {
StringBuilder key = new StringBuilder(LOCK_KEY + ":" + sign + ":");
@@ -70,9 +77,31 @@ public interface RedisCst {
return TABLE_CALL_NUMBER + shopId + ":" + callTableId;
}
/**
* 后厨总单
*
* @param machineId 打印机设备id
*/
static String kitchenAll(Long orderId, Long machineId) {
return kitchen.ALL + orderId + ":" + machineId;
}
static String getPrintOrderDetailKey(Long orderId, Long detailId) {
return PRINT_ORDER_DETAIL + orderId + ":" + detailId;
/**
* 后厨单个菜品单
*
* @param machineId 打印机设备id
*/
static String kitchenNormal(Long orderId, Long machineId, Long detailId) {
return kitchen.NORMAL + orderId + ":" + machineId + ":" + detailId;
}
/**
* 后厨总单
*
* @param machineId 打印机设备id
*/
static String kitchenRefundAll(Long orderId, Long machineId) {
return kitchen.REFUND_ALL + orderId + ":" + machineId;
}
static String getSongUrlKey(Long shopId) {

View File

@@ -53,30 +53,64 @@ public class HandoverRecordDTO implements Serializable {
* 员工姓名
*/
private String staffName;
/**
* 当班总收入
* 营业额
*/
private BigDecimal handAmount;
private BigDecimal turnover;
/**
* 现金收入
* 订单额
*/
private BigDecimal cashAmount;
private BigDecimal orderTurnover;
/**
* 微信收入
* 现金收款 cash_pay
*/
private BigDecimal wechatAmount;
private BigDecimal cash;
/**
* 支付宝收入
* 微信支付金额 wechat_mini
*/
private BigDecimal alipayAmount;
private BigDecimal wechat;
/**
* 会员支付
* 支付宝支付金额 alipay_mini
*/
private BigDecimal vipPay;
private BigDecimal alipay;
/**
* 会员充值
* 二维码收款 main_scan
*/
private BigDecimal vipRecharge;
private BigDecimal selfScan;
/**
* 扫码收款 back_scan
*/
private BigDecimal barScan;
/**
* 充值
*/
private BigDecimal recharge;
/**
* 挂账 credit_pay
*/
private BigDecimal owed;
/**
* 余额支付 vip_pay
*/
private BigDecimal balance;
/**
* 退款金额
*/
private BigDecimal refundAmount;
/**
* 退菜数量
*/
private BigDecimal returnDishCount;
/**
* 分类数据 json
*/
@@ -87,18 +121,7 @@ public class HandoverRecordDTO implements Serializable {
*/
@JSONField(serialize = false)
private String productData;
/**
* 快捷收款金额
*/
private BigDecimal quickInAmount;
/**
* 退款金额
*/
private BigDecimal refundAmount;
/**
* 挂账金额
*/
private BigDecimal creditAmount;
/**
* 订单数量
*/
@@ -124,11 +147,4 @@ public class HandoverRecordDTO implements Serializable {
*/
private List<HandoverProductListVo> productDataList;
public List<HandoverCategoryListVo> getCategoryDataList() {
return JSON.parseArray(categoryData, HandoverCategoryListVo.class);
}
public List<HandoverProductListVo> getProductDataList() {
return JSON.parseArray(productData, HandoverProductListVo.class);
}
}

View File

@@ -1,89 +0,0 @@
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-02-20
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ShopProdCategoryDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
private Long id;
/**
* 分类名称
*/
private String name;
/**
* 简称
*/
private String shortName;
/**
* 上级分类id-为0则表示是顶级
*/
private Long pid;
/**
* 图标
*/
private String pic;
/**
* 店铺Id
*/
private Long shopId;
/**
* 分类描述
*/
private String detail;
/**
* 排序
*/
private Integer sort;
/**
* 关键词
*/
private String keyWord;
/**
* 状态 0-禁用 1-启用
*/
private Integer status;
/**
* 创建时间
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
/**
* 更新时间
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}

View File

@@ -288,6 +288,10 @@ public class ShopInfoEditDTO {
* 数签子
*/
private Integer isCountStick;
/**
* 退菜退库存模式 1跟随商品分类 2 跟随单商品
*/
private Integer refundMode;
/**
* 企业id

View File

@@ -53,30 +53,69 @@ public class HandoverRecord implements Serializable {
* 员工姓名
*/
private String staffName;
/**
* 当班总收入
* 营业额
*/
private BigDecimal handAmount;
private BigDecimal turnover;
/**
* 现金收入
* 订单额
*/
private BigDecimal cashAmount;
private BigDecimal orderTurnover;
/**
* 微信收入
* 现金收款 cash_pay
*/
private BigDecimal wechatAmount;
private BigDecimal cash;
/**
* 支付宝收入
* 微信支付金额 wechat_mini
*/
private BigDecimal alipayAmount;
private BigDecimal wechat;
/**
* 会员支付
* 支付宝支付金额 alipay_mini
*/
private BigDecimal vipPay;
private BigDecimal alipay;
/**
* 会员充值
* 二维码收款 main_scan
*/
private BigDecimal vipRecharge;
private BigDecimal selfScan;
/**
* 扫码收款 back_scan
*/
private BigDecimal barScan;
/**
* 挂账 credit_pay
*/
private BigDecimal owed;
/**
* 余额支付 vip_pay
*/
private BigDecimal balance;
/**
* 充值
*/
private BigDecimal recharge;
/**
* 退款金额
*/
private BigDecimal refundAmount;
/**
* 退菜数量
*/
private BigDecimal returnDishCount;
/**
* 订单数量
*/
private Integer orderCount;
/**
* 分类数据 json
*/
@@ -85,20 +124,4 @@ public class HandoverRecord implements Serializable {
* 商品数据 json
*/
private String productData;
/**
* 快捷收款金额
*/
private BigDecimal quickInAmount;
/**
* 退款金额
*/
private BigDecimal refundAmount;
/**
* 挂账金额
*/
private BigDecimal creditAmount;
/**
* 订单数量
*/
private Integer orderCount;
}

View File

@@ -4,16 +4,15 @@ 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 java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 打印机设备 实体类。
*
@@ -21,7 +20,7 @@ import lombok.NoArgsConstructor;
* @since 2025-02-20
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("tb_print_machine")
@@ -30,8 +29,16 @@ public class PrintMachine implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@Id(keyType = KeyType.Auto)
private Integer id;
private Long id;
/**
* 店铺Id
*/
private Long shopId;
/**
* 设备名称
@@ -39,12 +46,22 @@ public class PrintMachine implements Serializable {
private String name;
/**
* 现在打印机支持USB 和 网络、蓝牙
* 连接方式 USB、云打印、局域网
*/
private String connectionType;
/**
* ip地址
* 打印类型 label标签 cash小票
*/
private String printType;
/**
* 打印机品牌 飞鹅/云想印
*/
private String brand;
/**
* ip地址/MAC地址
*/
private String address;
@@ -53,46 +70,6 @@ public class PrintMachine implements Serializable {
*/
private String port;
/**
* 打印类型分类label标签cash小票kitchen出品
*/
private String subType;
/**
* 状态 online
*/
private Integer status;
/**
* 店铺Id
*/
private Long shopId;
/**
* 分类Id
*/
private String categoryIds;
/**
* 现在打印机支持USB 和 网络两种
*/
private String contentType;
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
/**
* 分类
*/
private List<Object> categoryList;
/**
* 排序
*/
private Integer sort;
/**
* 小票尺寸 58mm 80mm
@@ -100,31 +77,58 @@ public class PrintMachine implements Serializable {
private String receiptSize;
/**
* 分类打印 0-所有 1-部分分类 2-部分商品
* 打印数量
*/
private Integer printNum;
/**
* 打印内容 数组
* GUEST_ORDER("客看单"),PRE_ORDER("预结算单"),ORDER("订单结算单"),RETURN_ORDER("退菜单"),REFUND_ORDER("退款单"),
* ALL_KITCHEN("后厨整单"),ONLY_KITCHEN("后厨分单"),REFUND_KITCHEN("后厨退菜单"),
* HANDOVER("交班单"),CALL("排队取号"),RECHARGE("储值单"),STOCK("出入库单"),STOCK_CHECK("盘点单"),
* PRODUCT_REPORT("商品报表"),DAY_REPORT("经营日报"),DAY_ORDER("日结单")
*/
private String printContentType;
/**
* 打印模式(厨房打印菜品) all整单 /only单个
*/
private String kitchenPrintMode;
/**
* 分类打印 0-所有 1-部分分类
*/
private String classifyPrint;
/**
* 打印数量 c1m1^2=顾客+商家[2张] m1^1=商家[1张] c1^1顾客[1张] c2m1^3顾客2+商家1[3张]
* 分类Id
*/
private String printQty;
private String categoryIds;
/**
* 打印方式 all-全部打印 normal-仅打印结账单「前台」one-仅打印制作单「厨房」
* 0 禁用 1启用
*/
private String printMethod;
private Integer status;
/**
* 打印类型JSON数组 refund-确认退款单 handover-交班单 queue-排队取号
*/
private String printType;
/**
* 媒体音开关 0-关 1-开
* 媒体声音开关 0关1开
*/
private Integer volumeSwitch;
/**
* 交班打印机开关 0-关 1-开
*/
private Integer handoverSwitch;
}
/**
* 创建时间
*/
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
/**
* 更新时间
*/
@Column(onUpdateValue = "now()")
private LocalDateTime updateTime;
/**
* 排序
*/
private Integer sort;
}

View File

@@ -135,6 +135,10 @@ public class ShopConfig implements Serializable {
* 数签子
*/
private Integer isCountStick;
/**
* 退菜退库存模式 1跟随商品分类 2 跟随单商品
*/
private Integer refundMode;
private String dingAppKey;

View File

@@ -361,6 +361,11 @@ public class ShopInfo implements Serializable {
*/
@Column(ignore = true)
private Integer isCountStick;
/**
* 退菜退库存模式 1跟随商品分类 2 跟随单商品
*/
@Column(ignore = true)
private Integer refundMode;
/**
* 运营端余额

View File

@@ -1,95 +0,0 @@
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.Data;
import lombok.NoArgsConstructor;
/**
* 商品分类 实体类。
*
* @author zs
* @since 2025-02-20
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table("tb_shop_prod_category")
public class ShopProdCategory implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 分类名称
*/
private String name;
/**
* 简称
*/
private String shortName;
/**
* 上级分类id-为0则表示是顶级
*/
private Long pid;
/**
* 图标
*/
private String pic;
/**
* 店铺Id
*/
private Long shopId;
/**
* 分类描述
*/
private String detail;
/**
* 排序
*/
private Integer sort;
/**
* 关键词
*/
private String keyWord;
/**
* 状态 0-禁用 1-启用
*/
private Integer status;
/**
* 创建时间
*/
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
/**
* 更新时间
*/
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
}

View File

@@ -51,14 +51,14 @@ public interface HandoverRecordService extends IService<HandoverRecord> {
*
* @return 交班记录ID
*/
Long handover();
HandoverRecord handover();
/**
* 交班打印小票
*
* @param handoverRecordId 交班记录id
* @param isPrint 是否打印 1-是 0-否
* @param record 交班记录
* @param isPrint 是否打印 1-是 0-否
*/
void printHandoverReceipt(Long handoverRecordId, Integer isPrint);
void printHandoverReceipt(HandoverRecord record, Integer isPrint);
}

View File

@@ -1,11 +1,7 @@
package com.czg.account.service;
import com.czg.account.dto.print.PrinterAddDTO;
import com.czg.account.dto.print.PrinterEditDTO;
import com.czg.account.dto.print.PrinterOrderDTO;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import com.czg.account.entity.PrintMachine;
import com.mybatisflex.core.service.IService;
/**
* 打印机设备 服务层。
@@ -15,9 +11,9 @@ import com.czg.account.entity.PrintMachine;
*/
public interface PrintMachineService extends IService<PrintMachine> {
boolean add(Long shopId, PrinterAddDTO printerAddDTO);
boolean add(Long shopId, PrintMachine printMachine);
Boolean edit(Long shopId, PrinterEditDTO printerEditDTO);
Boolean edit(Long shopId, PrintMachine printMachine);
}

View File

@@ -1,14 +0,0 @@
package com.czg.account.service;
import com.mybatisflex.core.service.IService;
import com.czg.account.entity.ShopProdCategory;
/**
* 商品分类 服务层。
*
* @author zs
* @since 2025-02-20
*/
public interface ShopProdCategoryService extends IService<ShopProdCategory> {
}

View File

@@ -55,17 +55,62 @@ public class HandoverTotalVo implements Serializable {
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime handoverTime;
/**
* 现金支付
* 营业额
*/
private BigDecimal cashAmount;
private BigDecimal turnover;
/**
* 订单额
*/
private BigDecimal orderTurnover;
/**
* 现金收款 cash_pay
*/
private BigDecimal cash;
/**
* 微信支付金额 wechat_mini
*/
private BigDecimal wechat;
/**
* 支付宝支付金额 alipay_mini
*/
private BigDecimal alipay;
/**
* 二维码收款 main_scan
*/
private BigDecimal selfScan;
/**
* 扫码收款 back_scan
*/
private BigDecimal barScan;
/**
* 充值
*/
private BigDecimal recharge;
/**
* 挂账 credit_pay
*/
private BigDecimal owed;
/**
* 余额支付 vip_pay
*/
private BigDecimal balance;
/**
* 退款金额
*/
private BigDecimal refundAmount;
/**
* 当班总收入(营业额)
* 退菜数量
*/
private BigDecimal handAmount;
private BigDecimal returnDishCount;
/**
* 订单数量
*/
@@ -74,4 +119,8 @@ public class HandoverTotalVo implements Serializable {
* 售出商品列表
*/
private List<HandoverProductListVo> detailList;
/**
* 售出商品分类列表
*/
private List<HandoverCategoryListVo> categoryList;
}

View File

@@ -20,11 +20,8 @@ public class OrderInfoPrintDTO implements Serializable {
@NotNull(message = "id不为空")
private Long id;
/**
* 0 菜品和结算单同时打印
* 1 预结算单
* 2 结算单
* 3 退菜/退款
* 4 交班
*/
@NotNull(message = "打印类型不为空")
private Integer type;

View File

@@ -50,6 +50,14 @@ public class OrderInfoRefundDTO implements Serializable {
* 是否是现金退款
*/
private boolean cash;
/**
* 是否打印退菜/退款票
*/
private boolean print;
/**
* 是否退库存
*/
private boolean refundStock;
private String refundReason;

View File

@@ -162,6 +162,8 @@ public class OrderDetail implements Serializable {
* 是否等叫
*/
private Integer isWaitCall;
@Column(ignore = true)
private Integer isAutoSoldStock;
/**
* 套餐商品选择信息

View File

@@ -2,6 +2,7 @@ package com.czg.order.service;
import cn.hutool.core.exceptions.ValidateException;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.entity.ShopInfo;
import com.czg.exception.CzgException;
import com.czg.exception.OrderCancelException;
import com.czg.exception.OrderValidateException;
@@ -21,6 +22,7 @@ import org.jetbrains.annotations.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 订单表 服务层。
@@ -73,4 +75,9 @@ public interface OrderInfoCustomService {
Boolean upOrderDetail(Long shopId, OrderDetailStatusDTO detailStatusDTO);
/**
* 退单库存问题
*/
void refundStock(ShopInfo shopInfo, Long orderId, Map<Long,BigDecimal> products, boolean refundStock);
}

View File

@@ -1,6 +1,7 @@
package com.czg.order.service;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.entity.HandoverRecord;
import com.czg.account.vo.HandoverCategoryListVo;
import com.czg.account.vo.HandoverProductListVo;
@@ -15,126 +16,6 @@ import java.util.List;
*/
public interface OrderInfoRpcService {
/**
* 交班现金支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 现金支付总额
*/
BigDecimal getHandoverCashAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班微信支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 现金支付总额
*/
BigDecimal getHandoverWechatAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班支付宝支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 支付宝支付总额
*/
BigDecimal getHandoverAlipayAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班VIP支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return VIP支付总额
*/
BigDecimal getHandoverVipPayAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班VIP充值统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return VIP充值总额
*/
BigDecimal getHandoverVipChargeAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班快捷支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 快捷支付总额
*/
BigDecimal getHandoverQuickPayAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班退款统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 退款总额
*/
BigDecimal getHandoverRefundAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班挂账统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 挂账总额
*/
BigDecimal getHandoverCreditAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班营业额统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 营业额
*/
BigDecimal getHandoverTotalAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班订单数统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 交班订单数
*/
int getHandoverOrderNum(Long shopId, String loginTime, String handoverTime);
/**
* 交班售出商品明细
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 交班售出商品明细
*/
List<HandoverProductListVo> getHandoverDetailList(Long shopId, String loginTime, String handoverTime);
/**
* 交班售出商品分类统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 售出商品分类统计
*/
List<HandoverCategoryListVo> getHandoverCategoryList(Long shopId, String loginTime, String handoverTime);
/**
* 订单支付成功回调 扣减商品库存及耗材库存
*
@@ -159,7 +40,47 @@ public interface OrderInfoRpcService {
/**
* 订单交班回调 发送答应交班小票消息至MQ
*
* @param handoverRecordId 交班记录id
* @param record 交班记录id
*/
void sendHandoverReceiptPrintMsgToMq(Long handoverRecordId);
void sendHandoverReceiptPrintMsgToMq(Long shopId, HandoverRecord record);
/**
* 交班售出商品明细
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 交班售出商品明细
*/
List<HandoverProductListVo> getHandoverDetailList(Long shopId, String loginTime, String handoverTime);
/**
* 交班售出商品分类统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 售出商品分类统计
*/
List<HandoverCategoryListVo> getHandoverCategoryList(Long shopId, String loginTime, String handoverTime);
//---------------------------------------------------------------------------------------->
/**
* 支付金额统计
* 营业额为 订单收款额度 不包括充值
*/
HandoverRecord getOnlinePayTypeDate(Long shopId, String loginTime, String handoverTime);
/**
* 订单退菜数量
*/
BigDecimal countReturnDish(Long shopId, String loginTime, String handoverTime);
/**
* 会员充值金额 退款金额
*/
HandoverRecord countShopUserFlow(Long shopId, String loginTime, String handoverTime);
}

View File

@@ -26,6 +26,7 @@ public class OrderDetailSmallVO implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Long productId;
private String productImg;
private String productName;
private String skuName;

View File

@@ -0,0 +1,158 @@
package com.czg.print;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
/**
* 经营日报
* @author Administrator
*/
@Data
@Accessors(chain = true)
public class DayReportPrintDTO {
/**
* 店铺名称
*/
private String shopName;
/**
* 操作人
*/
private String operator;
/**
* 统计时间
*/
private String statisticsTime;
/**
* 退款金额
*/
private BigDecimal refundAmount;
/**
* 退菜数量
*/
private Long returnDishCount;
/**
* 营业额
*/
private TurnoverSts turnover;
/**
* 订单
*/
private OrderSts order;
/**
* 数据统计
*/
private Sts sts;
/**
* 营业额 类
*/
@Data
@Accessors(chain = true)
public static class TurnoverSts {
/**
* 营业额
*/
private BigDecimal turnover;
/**
* 微信支付金额
*/
private BigDecimal wechat;
/**
* 支付宝支付金额
*/
private BigDecimal alipay;
/**
* 二维码收款
*/
private BigDecimal selfScan;
/**
* 扫码收款
*/
private BigDecimal barScan;
/**
* 现金收款
*/
private BigDecimal cash;
/**
* 充值
*/
private BigDecimal recharge;
/**
* 挂账
*/
private BigDecimal owed;
/**
* 余额支付
*/
private BigDecimal balance;
}
/**
* 订单 类
*/
@Data
@Accessors(chain = true)
public static class OrderSts {
/**
* 订单金额
*/
private BigDecimal orderAmount;
/**
* 订单总数
*/
private Long orderCount;
}
/**
* 数据统计 类
*/
@Data
@Accessors(chain = true)
public static class Sts {
/**
* 就餐人数
*/
private Long customerCount;
/**
* 客单价
* 实付金额(包含现金支付 包含会员支付 包含挂账)/就餐人数
* 没有具体人数时默认一桌按照1人计算
*/
private BigDecimal avgPayAmount;
/**
* 翻台率
* (订单数-桌台数)/桌台数*100%
*/
private BigDecimal turnoverRate;
/**
* 商品成本
*/
private BigDecimal productCostAmount;
/**
* 毛利率(订单实付金额-商品成本)/订单实付金额*100%
*/
private BigDecimal profitRate;
}
}

View File

@@ -0,0 +1,44 @@
package com.czg.print;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 订单打印实体
* @author ww
*/
@Data
@Accessors(chain = true)
public class OrderPrintDTO {
// 打印标题 结算单/客看单/预结算单 退菜单/退款单
private String printTitle;
private String shopName;
//打印类型 收银-堂食
private String printType;
//台桌区域-台桌号
private String pickupNum;
private String orderNo;
//结账时间
private String tradeDate;
//操作人名称
private String operator;
private String payAmount;
private String originalAmount;
private String payType;
private String remark;
//取餐码
private String outNumber;
private String discountAmount;
private String seatNum;
private String seatAmount;
private String packFee;
// 是否退款单
private boolean isReturn;
//退款单用
private String refundAmount;
//退款方式 现金退款/原路退回
private String refundType;
//退款原因
private String refundReason;
}

View File

@@ -0,0 +1,94 @@
package com.czg.print;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
* 商品报表打印实体
*
* @author ww
*/
@Data
@Accessors(chain = true)
public class ProductReportPrintDTO {
/**
* 店铺名称
*/
private String shopName;
/**
* 打印时间
*/
private String printTime;
/**
* 操作人
*/
private String operator;
/**
* 统计时间
*/
private String statisticsTime;
/**
* 总计商品数量
*/
private BigDecimal totalProductCount;
/**
* 总计实收金额
*/
private BigDecimal totalActualAmount;
/**
* 商品明细列表
* 分类名称,商品集合
*/
private Map<String, List<ProductItem>> items;
public ProductItem createProductItem(String productName, BigDecimal number, BigDecimal actualAmount, BigDecimal salesAmount) {
ProductItem item = new ProductItem();
item.setProductName(productName);
item.setNumber(number);
item.setActualAmount(actualAmount);
item.setSalesAmount(salesAmount);
return item;
}
/**
* 商品明细项
*
* @author ww
*/
@Data
@Accessors(chain = true)
public static class ProductItem {
/**
* 商品名称(第二列商品名称)
*/
private String productName;
/**
* 数量(第三列数量)
*/
private BigDecimal number;
/**
* 实收(第四列)
*/
private BigDecimal actualAmount;
/**
* 销售额(第五列)
*/
private BigDecimal salesAmount;
}
}

View File

@@ -0,0 +1,44 @@
package com.czg.print;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 储值单
* @author ww
*/
@Data
@Accessors(chain = true)
public class RechargePrintDTO {
//店铺名称
private String shopName;
private String userId;
private String userName;
private String userPhone;
//支付时间
private LocalDateTime payTime;
//充值金额
private BigDecimal rechargeAmount;
//赠送金额
private BigDecimal giftAmount;
//赠送积分
private BigDecimal giftPoints;
//赠送优惠券 张
private Integer giftCoupon;
//充值后余额
private BigDecimal balance;
//已付金额
private BigDecimal payAmount;
//支付方式
private String payType;
//操作员
private String operator;
//充值编号
private String rechargeId;
}

View File

@@ -0,0 +1,87 @@
package com.czg.print;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.List;
/**
* 盘点单打印实体
* @author ww
*/
@Data
@Accessors(chain = true)
public class StockCheckPrintDTO {
/**
* 店铺名称
*/
private String shopName;
/**
* 耗材明细列表
*/
private List<StockCheckItem> items;
/**
* 账存数量
*/
private Integer winLossNumberCount;
/**
* 盈亏金额
*/
private BigDecimal winLossAmount;
/**
* 备注
*/
private String remark;
/**
* 操作员
*/
private String operator;
public StockCheckItem createStockCheckItem(String consName, BigDecimal price, String unit, BigDecimal actualNumber, BigDecimal winLossNumber) {
return new StockCheckItem(consName, price, unit, actualNumber, winLossNumber);
}
/**
* 入库耗材明细
*
* @author ww
*/
@Data
@Accessors(chain = true)
@AllArgsConstructor
public static class StockCheckItem {
/**
* 耗材名称
*/
private String consName;
/**
* 单价
*/
private BigDecimal price;
/**
* 单位
*/
private String unit;
/**
* 实际数
*/
private BigDecimal actualNumber;
/**
* 盈亏数
*/
private BigDecimal winLossNumber;
}
}

View File

@@ -0,0 +1,101 @@
package com.czg.print;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
/**
* 入库打印单
*
* @author ww
*/
@Data
@Accessors(chain = true)
public class StockPrintDTO {
//IN OUT
private String type;
/**
* 店铺名称
*/
private String shopName;
/**
* 出入库时间
*/
private LocalDateTime inStockTime;
/**
* 出入库耗材明细列表
*/
private List<InStockItem> items;
/**
* 耗材总种类数
*/
private Integer consCount;
/**
* 出入库总数量
*/
private BigDecimal stockNumberCount;
/**
* 总金额
*/
private BigDecimal amountCount;
/**
* 操作员
*/
private String operator;
/**
* 打印时间
*/
private LocalDateTime printTime;
public InStockItem createInStockItem(String consName, String unit, BigDecimal stockNumber, BigDecimal amount) {
InStockItem item = new InStockItem();
item.setConsName(consName);
item.setUnit(unit);
item.setStockNumber(stockNumber);
item.setAmount(amount);
return item;
}
/**
* 入库耗材明细
*
* @author ww
*/
@Data
@Accessors(chain = true)
public static class InStockItem {
/**
* 耗材名称
*/
private String consName;
/**
* 库存单位
*/
private String unit;
/**
* 出入数量
*/
private BigDecimal stockNumber;
/**
* 金额
*/
private BigDecimal amount;
}
}

View File

@@ -76,10 +76,6 @@ public class ConsInfoDTO implements Serializable {
* 是否检测耗材: 1 检测 0 不检测
*/
private Integer isStock;
/**
* 是否退款退回: 1 退回 0 不退回
*/
private Integer isRefundStock;
/**
* 第二单位
*/

View File

@@ -29,7 +29,7 @@ public class ProdConsRelationDTO implements Serializable {
/**
* 商品id
*/
@NotNull(message = "商品id不能为空", groups = DefaultGroup.class)
// @NotNull(message = "商品id不能为空", groups = DefaultGroup.class)
private Long productId;
/**
* 耗材id
@@ -41,6 +41,10 @@ public class ProdConsRelationDTO implements Serializable {
*/
@NotNull(message = "使用数量不能为空", groups = DefaultGroup.class)
private BigDecimal surplusStock;
/**
* 耗材预警值
*/
private BigDecimal conWarning;
/**
* 创建时间
*/

View File

@@ -108,10 +108,6 @@ public class ProductDTO implements Serializable {
* 套餐内容
*/
private Object groupSnap;
/**
* 库存警戒线
*/
private Integer warnLine;
/**
* 称重 价格/千克
*/
@@ -155,23 +151,22 @@ public class ProductDTO implements Serializable {
*/
@NotNull(message = "是否推荐不能为空", groups = DefaultGroup.class)
private Integer isHot;
/**
* 是否开启库存
*/
@NotNull(message = "库存开关不能为空", groups = DefaultGroup.class)
private Integer isStock;
/**
* 是否售罄
*/
private Integer isSoldStock;
/**
* 是否自动售罄
*/
private Integer isAutoSoldStock;
/**
* 退菜是否退库存 1退菜退库存 2仅退菜不退库存 3每次询问-退菜后弹窗提示
*/
private Integer refundMode;
/**
* 团购卷分类,可有多个分类
*/
private String groupCategoryId;
/**
* 商品级库存数量
*/
private Integer stockNumber;
/**
* 是否上架
*/
@@ -249,13 +244,6 @@ public class ProductDTO implements Serializable {
return JSON.parseArray(Convert.toStr(images, "[]"));
}
/**
* {"口味":[{"甜度":["少甜","中甜","多甜"]},{"辣度":["微辣","重辣","变态辣"]},{"小料":["葱花","香菜","折耳根"]}]}
*/
public Object getSelectSpecInfo() {
return JSON.parseObject(Convert.toStr(selectSpecInfo, "{}"));
}
public Object getGroupSnap() {
return JSON.parseArray(Convert.toStr(groupSnap, "[]"));
}
@@ -271,4 +259,10 @@ public class ProductDTO implements Serializable {
return "[]";
}
/**
* {"口味":[{"甜度":["少甜","中甜","多甜"]},{"辣度":["微辣","重辣","变态辣"]},{"小料":["葱花","香菜","折耳根"]}]}
*/
public Object getSelectSpecInfo() {
return JSON.parseObject(Convert.toStr(selectSpecInfo, "{}"));
}
}

View File

@@ -80,4 +80,8 @@ public class ShopProdCategoryDTO implements Serializable {
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
/**
* 退菜是否退库存 1退菜退库存 2仅退菜不退库存 3每次询问-退菜后弹窗提示
*/
private Integer refundMode;
}

View File

@@ -69,10 +69,6 @@ public class ConsInfo implements Serializable {
* 是否检测耗材: 1 检测 0 不检测
*/
private Integer isStock;
/**
* 是否退款退回: 1 退回 0 不退回
*/
private Integer isRefundStock;
/**
* 第二单位
*/

View File

@@ -39,10 +39,12 @@ public class ConsStockFlow implements Serializable {
*/
private Long vendorId;
/**
* {@link com.czg.product.enums.InOutTypeEnum}
* 出入库类型 in-入库 out-出库
*/
private String inOutType;
/**
* {@link com.czg.product.enums.InOutItemEnum}
* 出入库名目 manual-in:手动入库 manual-out:手动出库 win-in:盘盈入库 loss-out:盘亏出库 order-in:订单退款入库 order-out:订单消费出库 damage-out:损耗出库
*/
private String inOutItem;

View File

@@ -83,10 +83,6 @@ public class Product implements Serializable {
*/
private String groupSnap;
/**
* 库存警戒线
*/
private Integer warnLine;
/**
* 称重 价格/千克
*/
private BigDecimal weight;
@@ -119,9 +115,13 @@ public class Product implements Serializable {
*/
private Integer isHot;
/**
* 是否开启库存
* 是否自动售罄
*/
private Integer isStock;
private Integer isAutoSoldStock;
/**
* 退菜是否退库存 1退菜退库存 2仅退菜不退库存 3每次询问-退菜后弹窗提示
*/
private Integer refundMode;
/**
* 是否售罄
*/
@@ -131,10 +131,6 @@ public class Product implements Serializable {
*/
private String groupCategoryId;
/**
* 商品库存数量
*/
private Integer stockNumber;
/**
* 是否上架
*/
private Integer isSale;

View File

@@ -68,6 +68,10 @@ public class ShopProdCategory implements Serializable {
* 状态 0-禁用 1-启用
*/
private Integer status;
/**
* 退菜是否退库存 1退菜退库存 2仅退菜不退库存 3每次询问-退菜后弹窗提示
*/
private Integer refundMode;
/**
* 创建时间
*/

View File

@@ -31,6 +31,9 @@ public class ConsCheckStockParam implements Serializable {
*/
@NotBlank(message = "耗材名称不能为空", groups = DefaultGroup.class)
private String conName;
@NotBlank(message = "操作员不能为空", groups = DefaultGroup.class)
private String operator;
/**
* 账存数量
*/

View File

@@ -69,4 +69,9 @@ public class ConsInOutStockHeadParam implements Serializable {
* 未入库信息
*/
private List<SaleOrderDTO.Item> unInCons;
/**
* 操作员
*/
private String operator;
}

View File

@@ -0,0 +1,40 @@
package com.czg.product.param;
import com.czg.validator.group.DefaultGroup;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 商品上下架参数
*
* @author tankaikai
* @since 2025-02-18 17:46
*/
@Data
public class ProductIsAutoSaleParam implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 商品id
*/
@NotNull(message = "商品id能为空", groups = DefaultGroup.class)
private Long id;
/**
* 是否上下架 1-上架0-下架
*/
@NotNull(message = "自动售罄不能为空", groups = DefaultGroup.class)
@Min(value = 0, message = "自动售罄必须是0或1", groups = DefaultGroup.class)
@Max(value = 1, message = "自动售罄必须是0或1", groups = DefaultGroup.class)
private Integer isAutoSoldStock;
}

View File

@@ -1,46 +0,0 @@
package com.czg.product.param;
import com.alibaba.fastjson2.annotation.JSONField;
import com.czg.validator.group.DefaultGroup;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 商品修改库存
*
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-02-16
*/
@Data
public class ProductModifyStockParam implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
@NotNull(message = "ID不能为空", groups = DefaultGroup.class)
private Long id;
/**
* 库存数量
*/
@NotNull(message = "库存数量不能为空", groups = DefaultGroup.class)
@Min(value = 0, message = "库存数量不能小于0", groups = DefaultGroup.class)
@Max(value = Integer.MAX_VALUE, message = "库存数量不能大于" + Integer.MAX_VALUE, groups = DefaultGroup.class)
private Integer stockNumber;
/**
* 备注
*/
private String remark;
/**
* 店铺id
*/
@JSONField(serialize = false)
private Long shopId;
}

View File

@@ -5,6 +5,7 @@ import com.czg.product.entity.ConsInfo;
import com.czg.product.param.ConsInfoParam;
import com.czg.product.param.ConsSubUnitParam;
import com.czg.product.vo.ConsStatisticsVo;
import com.czg.product.vo.ConsStockRecord;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
@@ -33,6 +34,9 @@ public interface ConsInfoService extends IService<ConsInfo> {
*/
List<ConsInfoDTO> getConsInfoList(ConsInfoDTO param);
List<ConsStockRecord> getConsStockList(Long shopId);
/**
* 获取耗材信息详情
*
@@ -87,10 +91,6 @@ public interface ConsInfoService extends IService<ConsInfo> {
*/
void onOffConsInfo(Long id, Integer isStock);
/**
* 是否退款退回
*/
void isRefundStockConsInfo(Long id, Integer isRefundStock);
/**
* 修改耗材单位

View File

@@ -10,6 +10,7 @@ import com.czg.product.vo.ConsCheckStockRecordVo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import java.math.BigDecimal;
import java.util.List;
/**
@@ -66,6 +67,7 @@ public interface ConsStockFlowService extends IService<ConsStockFlow> {
/**
* 获取耗材库存变动记录
*
* @param param 查询参数
* @return 分页数据
*/
@@ -73,7 +75,16 @@ public interface ConsStockFlowService extends IService<ConsStockFlow> {
/**
* 保存库存变动记录
*
* @param entity 库存变动记录实体
*/
void saveFlow(ConsStockFlow entity);
void saveFlow(ConsStockFlow entity, BigDecimal conWarning);
/**
* 发送库存消息
*
* @param entity 库存变动记录实体
* @param warning 警戒值
*/
boolean sendStockMsg(ConsStockFlow entity, BigDecimal warning);
}

View File

@@ -26,8 +26,10 @@ public interface ProdConsRelationService extends IService<ProdConsRelation> {
* 保存商品耗材绑定关系
*
* @param dto 商品耗材绑定关系DTO
* @return 保存结果
*/
void saveProdConsRelation(ProdConsBindDTO dto);
List<ProdConsRelationDTO> selectListByProdId(Long prodId);
List<ProdConsRelationDTO> selectStockByProdId(Long prodId);
}

View File

@@ -1,9 +1,9 @@
package com.czg.product.service;
import com.czg.product.vo.ProductStockVO;
import com.czg.product.vo.ProductVO;
import java.util.List;
import java.util.Map;
/**
* 商品RPC远程调用服务接口
@@ -20,24 +20,23 @@ public interface ProductRpcService {
* @param orderId 订单ID
* @param dataList 库存扣减数据
*/
void paySuccessSubtractStock(Long shopId, Long orderId, List<Map<String, Object>> dataList);
void paySuccessSubtractStock(Long shopId, Long orderId, List<ProductStockVO> dataList);
/**
* 订单取消后恢复库存
*
* @param shopId 店铺id
* @param orderId 订单ID
* @param dataList 库存恢复数据
*/
void orderCancelRecoverStock(Long shopId, Long orderId, List<Map<String, Object>> dataList);
void orderCancelRecoverStock(Long shopId, Long orderId, List<ProductStockVO> list);
/**
* 订单退菜或退款后回退库存
* @param shopId 店铺id
* @param orderId 订单ID
* @param dataList 库存恢复数据
* @param list 库存恢复数据
*/
void orderRefundReturnStock(Long shopId, Long orderId, List<Map<String, Object>> dataList);
void orderRefundReturnStock(Long shopId, Long orderId, List<ProductStockVO> list);
List<ProductVO> listAndLowPrice(Long shopId, List<Long> productIds);

View File

@@ -3,8 +3,11 @@ package com.czg.product.service;
import com.czg.product.dto.ProductDTO;
import com.czg.product.entity.Product;
import com.czg.product.entity.ProductStockFlow;
import com.czg.product.enums.InOutItemEnum;
import com.czg.product.enums.InOutTypeEnum;
import com.czg.product.param.*;
import com.czg.product.vo.ProductStatisticsVo;
import com.czg.product.vo.ProductStockVO;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import jakarta.servlet.http.HttpServletResponse;
@@ -39,10 +42,11 @@ public interface ProductService extends IService<Product> {
/**
* 从缓存里面获取商品列表
*
* @param param 查询参数
* @param shopId 店铺ID
* @param categoryId 商品分类ID
* @return 商品列表数据
*/
List<ProductDTO> getProductCacheList(ProductDTO param);
List<ProductDTO> getProductCacheList(Long shopId, Long categoryId);
/**
* 清除某个商品分类的缓存
@@ -71,13 +75,6 @@ public interface ProductService extends IService<Product> {
*/
void updateProduct(ProductDTO dto);
/**
* 修改商品库存数量
*
* @param param 商品id及库存数量
*/
void updateProductStock(ProductModifyStockParam param);
/**
* 删除商品
*
@@ -100,6 +97,13 @@ public interface ProductService extends IService<Product> {
*/
void markProductIsSoldOut(ProductIsSoldOutParam param);
/**
* 标记商品自动售罄
*
* @param param 入参
*/
void markProductIsAutoSoldOut(Long shopId, ProductIsAutoSaleParam param);
/**
* 退货到库存
*
@@ -107,12 +111,6 @@ public interface ProductService extends IService<Product> {
*/
void refundToStock(ProdRefundToStockParam param);
/**
* 库存预警
*
* @param warnLine 预警线
*/
void stockWarning(Integer warnLine);
/**
* 商品报损
@@ -137,11 +135,7 @@ public interface ProductService extends IService<Product> {
Page<ProductStockFlow> findProductStockFlowPage(ProductStockFlowParam param);
/**
* 刷新商品库存
*
* @param param 查询条件
* @param records 商品数据集合
* 通过商品 进行耗材库存增减
*/
void refreshProductStock(ProductDTO param, List<ProductDTO> records);
void consStockByProduct(Long shopId, InOutTypeEnum type, InOutItemEnum item, List<ProductStockVO> products, Long orderId, String remark);
}

View File

@@ -12,5 +12,4 @@ import com.mybatisflex.core.service.IService;
*/
public interface ProductStockFlowService extends IService<ProductStockFlow> {
void saveFlow(ProductStockFlow entity);
}

View File

@@ -10,7 +10,6 @@ import com.mybatisflex.core.service.IService;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
/**
* 用户端商品Service
@@ -52,28 +51,6 @@ public interface UProductService extends IService<Product> {
*/
ShopProductSkuInfoVo getProductSkuInfo(ShopProductSkuParam param);
/**
* 刷新商品库存
*
* @param shopId 店铺id
*/
Map<Long, Integer> findShopProductStock(Long shopId);
/**
* 刷新商品库存
*
* @param shopId 店铺id
* @param productList 商品列表
*/
void refreshProductStock(Long shopId, List<ShopProductVo> productList);
/**
* 刷新商品库存
*
* @param productStock 商品库存
* @param productList 商品列表
*/
void refreshProductStock(Map<Long, Integer> productStock, List<ShopProductVo> productList);
/**
* 分组计算是否在可售时间内

View File

@@ -0,0 +1,20 @@
package com.czg.product.vo;
import com.mybatisflex.annotation.Column;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author ww
*/
@Data
public class ConsStockRecord {
@Column("id")
private Long consId;
//消耗值
private BigDecimal stockNumber;
private String conName;
//库存数
private BigDecimal currentStockNumber;
}

View File

@@ -0,0 +1,25 @@
package com.czg.product.vo;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* 产品库存VO
* @author ww
*/
@Data
public class ProductStockVO implements Serializable {
private Long productId;
private BigDecimal number;
public ProductStockVO() {
}
public ProductStockVO(Long productId, BigDecimal number) {
this.productId = productId;
this.number = number;
}
}

View File

@@ -67,27 +67,19 @@ public class ShopProductSkuInfoVo implements Serializable {
*/
private BigDecimal realSalesNumber;
/**
* 是否售罄同isSoldStock
*/
private Integer isPauseSale;
/**
* 商品库存
*/
private Integer stockNumber;
/**
* 是否售罄isPauseSale
* 是否售罄
*/
private Integer isSoldStock;
/**
* 是否开启库存
*/
private Integer isAutoSoldStock;
/**
* 退菜是否退库存 1退菜退库存 2仅退菜不退库存 3每次询问-退菜后弹窗提示
*/
private Integer refundMode;
/**
* 是否上架(同isGrounding)
*/
private Integer isSale;
/**
* 是否开启库存
*/
private Integer isStock;
/**
* 是否上架(同isSale)
*/
private Integer isGrounding;
}

View File

@@ -1,6 +1,8 @@
package com.czg.product.vo;
import com.czg.product.dto.ProdConsRelationDTO;
import com.czg.product.dto.ProdSkuDTO;
import com.czg.product.entity.ProdConsRelation;
import lombok.Data;
import java.io.Serial;
@@ -59,9 +61,9 @@ public class ShopProductVo implements Serializable {
*/
private Integer isSoldStock;
/**
* 库存数量
* 是否自动售罄 1-是 0-否
*/
private Integer stockNumber;
private Integer isAutoSoldStock;
/**
* 商品类型 single-单规格商品 sku-多规格商品 package-套餐商品 weight-称重商品 coupon-团购券
*/
@@ -90,6 +92,8 @@ public class ShopProductVo implements Serializable {
* 商品规格列表
*/
private List<ProdSkuDTO> skuList;
private List<ProdConsRelation> consList;
/**
* 商品每周销售日 如Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
*/
@@ -114,8 +118,4 @@ public class ShopProductVo implements Serializable {
* 店铺id
*/
private Long shopId;
/**
* 是否开启库存
*/
private Integer isStock;
}

View File

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

View File

@@ -11,7 +11,7 @@ public enum ShopUserFlowBizEnum {
// 会员充值
CASH_IN("cashIn", "会员充值"),
CASHBACK("cashback", "消费返现"),
CASHBACK_REFUND("cashback_refund", "消费返现扣减"),
CASHBACK_REFUND("cashbackRefund", "消费返现扣减"),
FREE_IN("freeIn", "霸王餐充值"),
// 重置奖励
@@ -21,7 +21,7 @@ public enum ShopUserFlowBizEnum {
// 支付宝小程序重置
ALIPAY_IN("alipayIn", "支付宝小程序充值"),
// 订单支付奖励
ORDER_PAY("orderPay", "订单支付奖励"),
ORDER_PAY("orderPay", "订单支付"),
// 订单退款
ORDER_REFUND("orderRefund", "订单退款"),
// 充值退款

View File

@@ -1,14 +0,0 @@
package com.czg.service.account.mapper;
import com.mybatisflex.core.BaseMapper;
import com.czg.account.entity.ShopProdCategory;
/**
* 商品分类 映射层。
*
* @author zs
* @since 2025-02-20
*/
public interface ShopProdCategoryMapper extends BaseMapper<ShopProdCategory> {
}

View File

@@ -29,7 +29,6 @@ import jakarta.annotation.Resource;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.io.ByteArrayOutputStream;
import java.util.*;
@@ -42,7 +41,7 @@ import java.util.stream.Collectors;
* @author zs
* @since 2025-02-21
*/
@Service
@DubboService
public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable> implements CallTableService {
@DubboReference
private SysParamsService sysParamsService;
@@ -222,7 +221,7 @@ public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable
callQueueService.save(callQueue);
// 打印排号票信息
rabbitPublisher.printCallNumTicket(callQueue.getId());
rabbitPublisher.sendOtherPrintMsg(callQueue.getShopId(), callQueue, "CALL");
return new CallTableNumDTO().setTableName(callTable.getName()).setTableNote(callTable.getNote())
.setCallNum(callQueue.getCallNum()).setQueueId(callQueue.getId());
@@ -342,6 +341,7 @@ public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable
}
return 1;
}
private String getStrByState(Integer state) {
return switch (state) {
case -1 -> "已取消";

View File

@@ -1,18 +1,20 @@
package com.czg.service.account.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.czg.account.dto.HandoverRecordDTO;
import com.czg.account.entity.HandoverRecord;
import com.czg.account.service.HandoverRecordService;
import com.czg.account.vo.HandoverCategoryListVo;
import com.czg.account.vo.HandoverProductListVo;
import com.czg.account.vo.HandoverTotalVo;
import com.czg.constants.SystemConstants;
import com.czg.exception.CzgException;
import com.czg.order.service.OrderInfoRpcService;
import com.czg.sa.StpKit;
import com.czg.service.account.mapper.HandoverRecordMapper;
@@ -24,7 +26,6 @@ import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@@ -40,53 +41,40 @@ public class HandoverRecordServiceImpl extends ServiceImpl<HandoverRecordMapper,
@DubboReference
private OrderInfoRpcService orderInfoRpcService;
private QueryWrapper buildQueryWrapper(HandoverRecordDTO param) {
QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
if (StrUtil.isNotEmpty(param.getBeginDate())) {
queryWrapper.ge(HandoverRecord::getHandoverTime, param.getBeginDate() + " 00:00:00");
}
if (StrUtil.isNotEmpty(param.getEndDate())) {
queryWrapper.le(HandoverRecord::getHandoverTime, param.getEndDate() + " 23:59:59");
}
Long shopId = StpKit.USER.getShopId(0L);
queryWrapper.eq(HandoverRecord::getShopId, shopId);
queryWrapper.isNotNull(HandoverRecord::getHandoverTime);
queryWrapper.orderBy(HandoverRecord::getId, false);
return queryWrapper;
}
@Override
public Page<HandoverRecordDTO> getHandoverRecordPage(String beginDate, String endDate) {
HandoverRecordDTO param = new HandoverRecordDTO();
param.setBeginDate(beginDate);
param.setEndDate(endDate);
QueryWrapper queryWrapper = buildQueryWrapper(param);
QueryWrapper queryWrapper = query().eq(HandoverRecord::getShopId, StpKit.USER.getShopId());
if (StrUtil.isNotEmpty(param.getBeginDate())) {
queryWrapper.ge(HandoverRecord::getHandoverTime, param.getBeginDate() + " 00:00:00");
}
if (StrUtil.isNotEmpty(param.getEndDate())) {
queryWrapper.le(HandoverRecord::getHandoverTime, param.getEndDate() + " 23:59:59");
}
return super.pageAs(PageUtil.buildPage(), queryWrapper, HandoverRecordDTO.class);
}
@Override
public List<HandoverProductListVo> getHandoverProductListById(Long id) {
Long shopId = StpKit.USER.getShopId(0L);
HandoverRecord data = super.getOne(query().eq(HandoverRecord::getId, id).eq(HandoverRecord::getShopId, shopId));
if (data == null) {
Long shopId = StpKit.USER.getShopId();
HandoverRecord data = getOne(query().eq(HandoverRecord::getId, id).eq(HandoverRecord::getShopId, shopId));
if (data == null || data.getProductData() == null) {
return List.of();
}
String productData = data.getProductData();
if (StrUtil.isBlank(productData)) {
return List.of();
}
return JSON.parseArray(productData, HandoverProductListVo.class);
return JSON.parseArray(data.getProductData(), HandoverProductListVo.class);
}
@Override
public HandoverTotalVo totalHandoverData() {
Long shopId = StpKit.USER.getShopId(0L);
Long shopId = StpKit.USER.getShopId();
LocalDateTime handoverTime = LocalDateTime.now();
HandoverRecord record = super.getOne(query().eq(HandoverRecord::getShopId, shopId).isNull(HandoverRecord::getHandoverTime));
HandoverTotalVo data = new HandoverTotalVo();
if (record == null) {
return data;
throw new CzgException("未处在当班状态");
}
data.setId(record.getId());
data.setShopId(record.getShopId());
@@ -98,11 +86,21 @@ public class HandoverRecordServiceImpl extends ServiceImpl<HandoverRecordMapper,
data.setHandoverTime(handoverTime);
String loginTimeStr = LocalDateTimeUtil.formatNormal(record.getLoginTime());
String handoverTimeStr = LocalDateTimeUtil.formatNormal(handoverTime);
data.setCashAmount(sumCashAmount(shopId, loginTimeStr, handoverTimeStr));
data.setRefundAmount(sumRefundAmount(shopId, loginTimeStr, handoverTimeStr));
data.setHandAmount(sumHandAmount(shopId, loginTimeStr, handoverTimeStr));
data.setOrderCount(countOrderNum(shopId, loginTimeStr, handoverTimeStr));
data.setDetailList(getDetailList(shopId, loginTimeStr, handoverTimeStr));
data.setDetailList(orderInfoRpcService.getHandoverDetailList(shopId, loginTimeStr, handoverTimeStr));
data.setCategoryList(orderInfoRpcService.getHandoverCategoryList(shopId, loginTimeStr, handoverTimeStr));
HandoverRecord onlinePayTypeDate = orderInfoRpcService.getOnlinePayTypeDate(shopId, loginTimeStr, handoverTimeStr);
// 合并结果
CopyOptions copyOptions = CopyOptions.create().setIgnoreNullValue(true);
if (onlinePayTypeDate != null) {
BeanUtil.copyProperties(onlinePayTypeDate, data, copyOptions);
data.setTurnover(onlinePayTypeDate.getOrderTurnover());
}
HandoverRecord handoverRecord = orderInfoRpcService.countShopUserFlow(shopId, loginTimeStr, handoverTimeStr);
if (handoverRecord != null) {
data.setTurnover(NumberUtil.add(data.getTurnover(), handoverRecord.getRecharge()));
data.setRefundAmount(NumberUtil.add(data.getRefundAmount(), handoverRecord.getRefundAmount()));
}
data.setReturnDishCount(orderInfoRpcService.countReturnDish(shopId, loginTimeStr, handoverTimeStr));
return data;
}
@@ -113,57 +111,25 @@ public class HandoverRecordServiceImpl extends ServiceImpl<HandoverRecordMapper,
return;
}
entity.setLoginTime(LocalDateTime.now());
super.save(entity);
save(entity);
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long handover() {
Long shopId = StpKit.USER.getShopId(0L);
public HandoverRecord handover() {
HandoverTotalVo data = totalHandoverData();
LocalDateTime loginTime = data.getLoginTime();
LocalDateTime handoverTime = data.getHandoverTime();
String loginTimeStr = LocalDateTimeUtil.formatNormal(loginTime);
String handoverTimeStr = LocalDateTimeUtil.formatNormal(handoverTime);
HandoverRecord entity = BeanUtil.copyProperties(data, HandoverRecord.class);
entity.setWechatAmount(orderInfoRpcService.getHandoverWechatAmount(shopId, loginTimeStr, handoverTimeStr));
entity.setAlipayAmount(orderInfoRpcService.getHandoverAlipayAmount(shopId, loginTimeStr, handoverTimeStr));
entity.setVipPay(orderInfoRpcService.getHandoverVipPayAmount(shopId, loginTimeStr, handoverTimeStr));
entity.setVipRecharge(orderInfoRpcService.getHandoverVipChargeAmount(shopId, loginTimeStr, handoverTimeStr));
entity.setQuickInAmount(orderInfoRpcService.getHandoverQuickPayAmount(shopId, loginTimeStr, handoverTimeStr));
entity.setCreditAmount(orderInfoRpcService.getHandoverCreditAmount(shopId, loginTimeStr, handoverTimeStr));
List<HandoverCategoryListVo> categoryData = orderInfoRpcService.getHandoverCategoryList(shopId, loginTimeStr, handoverTimeStr);
entity.setCategoryData(JSON.toJSONString(categoryData, JSONWriter.Feature.WriteMapNullValue));
entity.setCategoryData(JSON.toJSONString(data.getCategoryList(), JSONWriter.Feature.WriteMapNullValue));
List<HandoverProductListVo> productData = data.getDetailList();
entity.setProductData(JSON.toJSONString(productData, JSONWriter.Feature.WriteMapNullValue));
super.updateById(entity);
return entity.getId();
return entity;
}
@Override
public void printHandoverReceipt(Long handoverRecordId, Integer isPrint) {
public void printHandoverReceipt(HandoverRecord record, Integer isPrint) {
if (isPrint == SystemConstants.OneZero.ONE) {
orderInfoRpcService.sendHandoverReceiptPrintMsgToMq(handoverRecordId);
orderInfoRpcService.sendHandoverReceiptPrintMsgToMq(record.getShopId(), record);
}
}
private BigDecimal sumCashAmount(Long shopId, String loginTime, String handoverTime) {
return orderInfoRpcService.getHandoverCashAmount(shopId, loginTime, handoverTime);
}
private BigDecimal sumRefundAmount(Long shopId, String loginTime, String handoverTime) {
return orderInfoRpcService.getHandoverRefundAmount(shopId, loginTime, handoverTime);
}
private BigDecimal sumHandAmount(Long shopId, String loginTime, String handoverTime) {
return orderInfoRpcService.getHandoverTotalAmount(shopId, loginTime, handoverTime);
}
private int countOrderNum(Long shopId, String loginTime, String handoverTime) {
return orderInfoRpcService.getHandoverOrderNum(shopId, loginTime, handoverTime);
}
private List<HandoverProductListVo> getDetailList(Long shopId, String loginTime, String handoverTime) {
return orderInfoRpcService.getHandoverDetailList(shopId, loginTime, handoverTime);
}
}

View File

@@ -7,15 +7,16 @@ import com.czg.account.dto.pad.*;
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.constants.SystemConstants;
import com.czg.exception.CzgException;
import com.czg.product.entity.ProdSku;
import com.czg.product.entity.Product;
import com.czg.product.entity.ShopProdCategory;
import com.czg.product.service.ProdSkuService;
import com.czg.product.service.ProductRpcService;
import com.czg.product.service.ProductService;
import com.czg.product.service.ShopProdCategoryService;
import com.czg.product.vo.ProductVO;
import com.czg.service.account.mapper.PadProductCategoryDetailMapper;
import com.czg.utils.PageUtil;
@@ -50,7 +51,7 @@ public class PadProdServiceImpl implements PadProdService {
private ProductRpcService productRpcService;
@DubboReference
private ProdSkuService prodSkuService;
@Resource
@DubboReference
private ShopProdCategoryService shopProdCategoryService;
@Resource
private PadLayoutService padLayoutService;

View File

@@ -3,8 +3,6 @@ package com.czg.service.account.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.czg.account.dto.print.PrinterAddDTO;
import com.czg.account.dto.print.PrinterEditDTO;
import com.czg.account.entity.PrintMachine;
import com.czg.account.service.PrintMachineService;
import com.czg.exception.CzgException;
@@ -20,32 +18,36 @@ import org.apache.dubbo.config.annotation.DubboService;
* @since 2025-02-20
*/
@DubboService
public class PrintMachineServiceImpl extends ServiceImpl<PrintMachineMapper, PrintMachine> implements PrintMachineService{
public class PrintMachineServiceImpl extends ServiceImpl<PrintMachineMapper, PrintMachine> implements PrintMachineService {
@Override
public boolean add(Long shopId, PrinterAddDTO dto) {
public boolean add(Long shopId, PrintMachine dto) {
//分类打印选择部分打印时必传JsonArray字符串数据 如:[{"id":125,"name":"意式咖啡"},{"id":127,"name":"饮品"}]
if ("1".equals(dto.getClassifyPrint()) || "2".equals(dto.getClassifyPrint())) {
if (StrUtil.isBlank(dto.getCategoryList())) {
if ("1".equals(dto.getClassifyPrint())) {
if (StrUtil.isBlank(dto.getCategoryIds()) || dto.getCategoryIds().length() < 3) {
throw new CzgException("分类打印选择部分打印时,必须勾选需要部分打印的菜品");
}
if (!JSONUtil.isTypeJSONArray(dto.getCategoryList())) {
if (!JSONUtil.isTypeJSONArray(dto.getCategoryIds())) {
throw new CzgException("传递的部分打印菜品数据不合法");
}
if (StrUtil.isBlank(dto.getCategoryIds())) {
throw new CzgException("分类打印选择部分打印时传递的部分打印菜品id数据不能为空");
}
} else {
dto.setCategoryIds(null);
dto.setCategoryList(null);
}
PrintMachine entity = BeanUtil.copyProperties(dto, PrintMachine.class);
entity.setShopId(shopId);
return save(entity);
return save(dto);
}
@Override
public Boolean edit(Long shopId, PrinterEditDTO printerEditDTO) {
public Boolean edit(Long shopId, PrintMachine printerEditDTO) {
if ("1".equals(printerEditDTO.getClassifyPrint())) {
if (StrUtil.isBlank(printerEditDTO.getCategoryIds()) || printerEditDTO.getCategoryIds().length() < 3) {
throw new CzgException("分类打印选择部分打印时,必须勾选需要部分打印的菜品");
}
if (!JSONUtil.isTypeJSONArray(printerEditDTO.getCategoryIds())) {
throw new CzgException("传递的部分打印菜品数据不合法");
}
} else {
printerEditDTO.setCategoryIds(null);
}
PrintMachine printMachine = getOne(new QueryWrapper().eq(PrintMachine::getShopId, shopId).eq(PrintMachine::getId, printerEditDTO.getId()));
if (printMachine == null) {
throw new CzgException("打印机不存在");

View File

@@ -1,18 +0,0 @@
package com.czg.service.account.service.impl;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.czg.account.entity.ShopProdCategory;
import com.czg.account.service.ShopProdCategoryService;
import com.czg.service.account.mapper.ShopProdCategoryMapper;
import org.springframework.stereotype.Service;
/**
* 商品分类 服务层实现。
*
* @author zs
* @since 2025-02-20
*/
@Service
public class ShopProdCategoryServiceImpl extends ServiceImpl<ShopProdCategoryMapper, ShopProdCategory> implements ShopProdCategoryService{
}

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.czg.service.account.mapper.ShopProdCategoryMapper">
</mapper>

View File

@@ -1,10 +1,12 @@
package com.czg.service.market.mapper;
import com.czg.account.entity.HandoverRecord;
import com.czg.account.vo.HandoverCategoryListVo;
import com.czg.account.vo.HandoverProductListVo;
import com.czg.order.entity.OrderInfo;
import com.mybatisflex.core.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.math.BigDecimal;
import java.util.List;
@@ -16,105 +18,6 @@ import java.util.List;
* @since 2025-02-13
*/
public interface OrderInfoMapper extends BaseMapper<OrderInfo> {
/**
* 交班现金支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 现金支付总额
*/
BigDecimal getHandoverCashAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班微信支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 现金支付总额
*/
BigDecimal getHandoverWechatAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班支付宝支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 支付宝支付总额
*/
BigDecimal getHandoverAlipayAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班VIP支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return VIP支付总额
*/
BigDecimal getHandoverVipPayAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班VIP充值统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return VIP充值总额
*/
BigDecimal getHandoverVipChargeAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班快捷支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 快捷支付总额
*/
BigDecimal getHandoverQuickPayAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班退款统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 退款总额
*/
BigDecimal getHandoverRefundAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班挂账统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 挂账总额
*/
BigDecimal getHandoverCreditAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班营业额统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 营业额
*/
BigDecimal getHandoverTotalAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班订单数统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 交班订单数
*/
int getHandoverOrderNum(Long shopId, String loginTime, String handoverTime);
/**
* 交班售出商品明细
@@ -140,4 +43,49 @@ public interface OrderInfoMapper extends BaseMapper<OrderInfo> {
int updatePayOrderId(@Param("orderId") Long orderId, @Param("paymentId") Long paymentId, @Param("payType") String payType, @Param("remark") String remark);
}
/**
* 订单支付方式统计 当日实时数据
*/
@Select("SELECT" +
" SUM(tb_order_info.pay_amount) AS orderTurnover," +
" SUM(CASE WHEN pay_type = 'main_scan' THEN pay_amount ELSE 0 END) AS selfScan," +
" SUM(CASE WHEN pay_type = 'back_scan' THEN pay_amount ELSE 0 END) AS barScan," +
" SUM(CASE WHEN pay_type = 'wechat_mini' THEN pay_amount ELSE 0 END) AS wechat," +
" SUM(CASE WHEN pay_type = 'alipay_mini' THEN pay_amount ELSE 0 END) AS alipay," +
" SUM(CASE WHEN pay_type = 'vip_pay' THEN pay_amount ELSE 0 END) AS balance," +
" SUM(CASE WHEN pay_type = 'cash_pay' THEN pay_amount ELSE 0 END) AS cash," +
" SUM(CASE WHEN pay_type = 'credit_pay' THEN pay_amount ELSE 0 END) AS owed," +
" IFNULL(SUM(refund_amount), 0) as refundAmount," +
" count(1) as orderCount " +
" FROM" +
" tb_order_info " +
" WHERE" +
" shop_id = #{shopId} " +
"and create_time >= #{loginTime} and create_time <= #{handoverTime} " +
"and paid_time is not null ")
HandoverRecord getOnlinePayTypeDate(Long shopId, String loginTime, String handoverTime);
/**
* 订单退菜数量
*/
@Select("SELECT" +
" SUM(o.return_num) AS returnDishCount " +
" FROM" +
" tb_order_info left join tb_order_detail o on tb_order_info.id = o.order_id" +
" WHERE" +
" tb_order_info.shop_id = #{shopId} " +
"and tb_order_info.create_time >= #{loginTime} and tb_order_info.create_time <= #{handoverTime} " +
"and tb_order_info.paid_time is not null ")
BigDecimal countReturnDish(Long shopId, String loginTime, String handoverTime);
@Select("SELECT " +
" SUM(CASE WHEN biz_code IN ('cashIn', 'wechatIn', 'alipayIn', 'adminIn','freeIn') THEN amount ELSE 0 END) AS recharge," +
" SUM(CASE WHEN biz_code IN ('rechargeRefund') THEN amount ELSE 0 END) AS refundAmount " +
"FROM `tb_shop_user_flow` " +
" WHERE" +
" shop_id = #{shopId} " +
"and create_time >= #{loginTime} and create_time <= #{handoverTime} ")
HandoverRecord countShopUserFlow(Long shopId, String loginTime, String handoverTime);
}

View File

@@ -45,39 +45,7 @@
where id = #{orderId};
</update>
<select id="getHandoverCashAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
and t1.pay_type = 'cash_pay'
</where>
</select>
<select id="getHandoverRefundAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.refund_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
</where>
</select>
<select id="getHandoverTotalAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
</where>
</select>
<select id="getHandoverOrderNum" resultType="java.lang.Integer">
SELECT
count(*)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
</where>
</select>
<select id="getHandoverDetailList" resultType="com.czg.account.vo.HandoverProductListVo">
SELECT
t2.product_id,
@@ -96,53 +64,7 @@
t2.product_id,
t2.sku_id
</select>
<select id="getHandoverWechatAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
and t1.pay_type = 'wechat_mini'
</where>
</select>
<select id="getHandoverAlipayAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
and t1.pay_type = 'alipay_mini'
</where>
</select>
<select id="getHandoverVipPayAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
and t1.pay_type = 'vip_pay'
</where>
</select>
<select id="getHandoverVipChargeAmount" resultType="java.math.BigDecimal">
select ifnull(sum(t1.amount), 0)
from tb_shop_user_flow t1
where t1.shop_id = #{shopId}
and t1.biz_code in ('cashIn', 'wechatIn', 'alipayIn', 'adminIn')
and t1.recharge_id is not null
<![CDATA[
AND t1.create_time >= str_to_date(#{loginTime}, '%Y-%m-%d %H:%i:%s')
AND t1.create_time <= str_to_date(#{handoverTime}, '%Y-%m-%d %H:%i:%s')
]]>
</select>
<select id="getHandoverQuickPayAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
and t1.pay_type in ('main_scan','back_scan')
</where>
</select>
<select id="getHandoverCategoryList" resultType="com.czg.account.vo.HandoverCategoryListVo">
SELECT case when t3.category_id is null then 0 else t3.category_id end as category_id,
case when t4.name is null then '未分类' else t4.name end as category_name,
@@ -158,13 +80,4 @@
</where>
GROUP BY t3.category_id
</select>
<select id="getHandoverCreditAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
and t1.pay_type = 'credit_pay'
</where>
</select>
</mapper>

View File

@@ -2,10 +2,12 @@ package com.czg.service.order.mapper;
import com.czg.account.vo.HandoverCategoryListVo;
import com.czg.account.vo.HandoverProductListVo;
import com.czg.product.vo.ConsStockRecord;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
* 订单表 映射层。
@@ -13,107 +15,7 @@ import java.util.List;
* @author ww
* @since 2025-02-13
*/
public interface OrderInfoCustomMapper{
/**
* 交班现金支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 现金支付总额
*/
BigDecimal getHandoverCashAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班微信支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 现金支付总额
*/
BigDecimal getHandoverWechatAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班支付宝支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 支付宝支付总额
*/
BigDecimal getHandoverAlipayAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班VIP支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return VIP支付总额
*/
BigDecimal getHandoverVipPayAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班VIP充值统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return VIP充值总额
*/
BigDecimal getHandoverVipChargeAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班快捷支付统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 快捷支付总额
*/
BigDecimal getHandoverQuickPayAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班退款统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 退款总额
*/
BigDecimal getHandoverRefundAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班挂账统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 挂账总额
*/
BigDecimal getHandoverCreditAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班营业额统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 营业额
*/
BigDecimal getHandoverTotalAmount(Long shopId, String loginTime, String handoverTime);
/**
* 交班订单数统计
*
* @param shopId 店铺id
* @param loginTime 上岗时间
* @param handoverTime 交班时间
* @return 交班订单数
*/
int getHandoverOrderNum(Long shopId, String loginTime, String handoverTime);
public interface OrderInfoCustomMapper {
/**
* 交班售出商品明细
@@ -138,4 +40,9 @@ public interface OrderInfoCustomMapper{
int decrMoney(@Param("id") Long id, @Param("amount") BigDecimal amount);
int updatePayOrderId(@Param("orderId") Long orderId, @Param("paymentId") Long paymentId, @Param("payType") String payType, @Param("remark") String remark);
List<ConsStockRecord> getConsByProductAndNum(
@Param("shopId") Long shopId,
@Param("productUsageMap") Map<Long, BigDecimal> productUsageMap
);
}

View File

@@ -1,20 +1,17 @@
package com.czg.service.order.print;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.czg.account.dto.HandoverRecordDTO;
import com.czg.account.entity.PrintMachine;
import com.czg.account.entity.ShopInfo;
import com.czg.order.entity.OrderDetail;
import com.czg.order.entity.OrderInfo;
import com.czg.service.order.enums.OrderStatusEnums;
import com.czg.print.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
@@ -22,9 +19,7 @@ import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -35,6 +30,7 @@ import java.util.Map;
*/
@Component
@Slf4j
@Qualifier("feiPrinter")
public class FeiPrinter extends PrinterHandler implements PrinterImpl {
// API 地址
@@ -67,57 +63,71 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
}
@Override
protected void normalDishesPrint(String operator, OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
String buildDishPrintData = buildDishPrintData(false, getPickupNum(orderInfo), DateUtil.format(orderDetail.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), orderDetail.getProductName(), orderDetail.getSkuName(),
orderDetail.getNum(), orderDetail.getRemark(), orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
protected void onlyKitchenPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
String buildDishPrintData = buildOnlyKitchenPrintData(getPickupNum(orderInfo), orderDetail);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
if (1 == machine.getVolumeSwitch()) {
voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
}
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
printMachineLogService.save(orderInfo.getId(), machine, "新订", buildDishPrintData, resp);
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(orderInfo.getId(), machine, "后厨商品", buildDishPrintData, resp);
}
@Override
protected void returnDishesPrint(String operator, OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
String buildDishPrintData = buildDishPrintData(true, getPickupNum(orderInfo), DateUtil.format(orderDetail.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), orderDetail.getProductName(), orderDetail.getSkuName(),
orderDetail.getReturnNum(), orderDetail.getRemark(), orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
public OrderPrintDTO allKitchenPrint(OrderInfo orderInfo, List<OrderDetail> orderDetails, PrintMachine machine) {
OrderPrintDTO orderPrintDTO = super.allKitchenPrint(orderInfo, orderDetails, machine);
String buildDishPrintData = buildAllKitchenPrintData(orderPrintDTO, orderDetails);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
printMachineLogService.save(orderInfo.getId(), machine, "厨房退菜", buildDishPrintData, resp);
if (1 == machine.getVolumeSwitch()) {
voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
}
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(orderInfo.getId(), machine, "后厨总单", buildDishPrintData, resp);
return null;
}
@Override
public PrintInfoDTO returnOrderPrint(String printTitle,String operator, String refundAmount, String refundReason, String refundType,
OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
PrintInfoDTO printInfoDTO = super.returnOrderPrint(printTitle,operator, refundAmount, refundReason, refundType, orderInfo, machine, detailList);
String data = buildRefundOrderPrintData(printInfoDTO, detailList);
public OrderPrintDTO returnKitchenPrint(String operator, OrderInfo orderInfo, List<OrderDetail> orderDetail, PrintMachine machine) {
OrderPrintDTO orderPrintDTO = super.returnKitchenPrint(operator, orderInfo, orderDetail, machine);
String buildDishPrintData = buildAllKitchenPrintData(orderPrintDTO, orderDetail);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
if (1 == machine.getVolumeSwitch()) {
voiceJson = "{\"bizType\":\"2\",\"content\":\"退菜消息,请及时处理\"}";
}
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(orderInfo.getId(), machine, "后厨退菜", buildDishPrintData, resp);
return null;
}
@Override
public OrderPrintDTO returnOrderPrint(String printTitle, String operator, String refundAmount, String refundReason, String refundType,
OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
OrderPrintDTO orderPrintDTO = super.returnOrderPrint(printTitle, operator, refundAmount, refundReason, refundType, orderInfo, machine, detailList);
String data = buildRefundOrderPrintData(orderPrintDTO, detailList);
sendOrderPrint(data, orderInfo.getId(), machine, "退款单");
return null;
}
@Override
public PrintInfoDTO guestOrderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
PrintInfoDTO printInfoDTO = super.guestOrderPrint(orderInfo, machine, detailList);
String data = buildGuestOrderPrintData(printInfoDTO, detailList);
public OrderPrintDTO guestOrderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
OrderPrintDTO orderPrintDTO = super.guestOrderPrint(orderInfo, machine, detailList);
String data = buildGuestOrderPrintData(orderPrintDTO, detailList);
sendOrderPrint(data, orderInfo.getId(), machine, "客看单");
return null;
}
@Override
public PrintInfoDTO preOrderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
PrintInfoDTO printInfoDTO = super.preOrderPrint(orderInfo, machine, detailList);
String data = buildOrderPrintData(printInfoDTO, detailList);
public OrderPrintDTO preOrderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
OrderPrintDTO orderPrintDTO = super.preOrderPrint(orderInfo, machine, detailList);
String data = buildOrderPrintData(orderPrintDTO, detailList);
sendOrderPrint(data, orderInfo.getId(), machine, "预结算单");
return null;
}
@Override
public PrintInfoDTO orderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
PrintInfoDTO printInfoDTO = super.orderPrint(orderInfo, machine, detailList);
String data = buildOrderPrintData(printInfoDTO, detailList);
public OrderPrintDTO orderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
OrderPrintDTO orderPrintDTO = super.orderPrint(orderInfo, machine, detailList);
String data = buildOrderPrintData(orderPrintDTO, detailList);
sendOrderPrint(data, orderInfo.getId(), machine, "结算单");
return null;
@@ -130,15 +140,60 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一条新的排号记录\"}";
}
String data = buildCallTicketData(shopName, tableName, callNum, preNum, codeUrl, shopNote, takeTime);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, "1");
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(machine, "叫号单", data, resp);
}
@Override
protected void handoverPrint(PrintMachine machine, HandoverRecordDTO record) {
protected void stockPrint(PrintMachine machine, String shopName, StockPrintDTO record) {
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
String data = buildStockData(record);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(machine, "IN".equals(record.getType()) ? "入库单" : "出库单", data, resp);
}
@Override
protected void dayReportPrint(PrintMachine machine, String shopName, DayReportPrintDTO record) {
record.setShopName(shopName);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
String data = buildDayReportData(record);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(machine, "经营日报单", data, resp);
}
@Override
protected void productReportPrint(PrintMachine machine, String shopName, ProductReportPrintDTO record) {
record.setShopName(shopName);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
String data = buildProductReportData(record);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(machine, "商品报表单", data, resp);
}
@Override
protected void rechargePrint(PrintMachine machine, String shopName, RechargePrintDTO record) {
record.setShopName(shopName);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
String data = buildRechargeData(record);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(machine, "储值单", data, resp);
}
@Override
protected void stockCheckPrint(PrintMachine machine, String shopName, StockCheckPrintDTO record) {
record.setShopName(shopName);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
String data = buildStockCheckData(record);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(machine, "盘点单", data, resp);
}
@Override
protected void handoverPrint(PrintMachine machine, String shopName, HandoverRecordDTO record) {
record.setShopName(shopName);
String string = buildHandoverData(record);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
sendPrintRequest(machine.getAddress(), string, voiceJson, "1");
sendPrintRequest(machine.getAddress(), string, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
}
/**
@@ -153,11 +208,7 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
if (1 == machine.getVolumeSwitch()) {
voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
}
String printerNum = "1";
if (StrUtil.isNotBlank(machine.getPrintQty())) {
printerNum = machine.getPrintQty().split("\\^")[1];
}
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, printerNum);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(orderId, machine, bizType, data, resp);
}
@@ -244,20 +295,4 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
}
return msg;
}
/**
* 计算优惠金额:优先使用 discountAllAmount如果为 null 则用原价 - 实付计算
*/
private String calculateDiscountAmount(OrderInfo orderInfo) {
if (orderInfo.getDiscountAllAmount() != null) {
return orderInfo.getDiscountAllAmount().toPlainString();
}
// 兜底计算:原价 + 餐位费 + 打包费 - 实付
BigDecimal originalTotal = orderInfo.getOriginAmount()
.add(orderInfo.getSeatAmount() != null ? orderInfo.getSeatAmount() : BigDecimal.ZERO)
.add(orderInfo.getPackFee() != null ? orderInfo.getPackFee() : BigDecimal.ZERO);
BigDecimal discount = originalTotal.subtract(orderInfo.getPayAmount());
return discount.compareTo(BigDecimal.ZERO) >= 0 ? discount.toPlainString() : "0.00";
}
}

View File

@@ -1,42 +1,56 @@
package com.czg.service.order.print;
import org.springframework.context.annotation.Bean;
import com.czg.exception.CzgException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 打印机责任链初始化
*
* @author Administrator
*/
@Slf4j
@Configuration
public class PrintConfig {
@Resource
private List<PrinterHandler> printers;
private ApplicationContext applicationContext;
// 直接使用实例变量,不需要静态
private Map<String, PrinterHandler> printerMap;
// 初始化责任链
@PostConstruct
public void initChain() {
// 检查打印处理器列表是否为空
if (printers != null && !printers.isEmpty()) {
for (int i = 0; i < printers.size() - 1; i++) {
// 设置当前处理器的下一个处理器
printers.get(i).setNextPrinter(printers.get(i + 1));
public void init() {
Map<String, PrinterHandler> printers = applicationContext.getBeansOfType(PrinterHandler.class);
printerMap = new ConcurrentHashMap<>();
printers.forEach((beanName, printer) -> {
String brand = printer.printerBrand;
if (brand != null && !brand.trim().isEmpty()) {
printerMap.put(brand, printer);
}
});
log.info("已注册打印机: {}", printerMap.keySet());
}
/**
* 获取打印机
*/
public PrinterHandler getPrinter(String key) {
PrinterHandler printer = printerMap.get(key);
if (printer == null) {
throw new CzgException("未找到打印机: " + key);
}
return printer;
}
@Bean
@Primary
public PrinterHandler printerHandler() {
// 返回责任链的起始处理器
return printers.getFirst();
}
}

View File

@@ -1,18 +1,14 @@
package com.czg.service.order.print;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import com.czg.account.dto.HandoverRecordDTO;
import com.czg.account.entity.PrintMachine;
import com.czg.account.entity.ShopInfo;
import com.czg.order.entity.OrderDetail;
import com.czg.order.entity.OrderInfo;
import com.czg.service.order.enums.OrderStatusEnums;
import com.mybatisflex.core.query.QueryWrapper;
import com.czg.print.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
@@ -20,8 +16,6 @@ import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
@@ -33,6 +27,7 @@ import java.util.*;
*/
@Slf4j
@Component
@Qualifier("yxyPrinter")
public class YxyPrinter extends PrinterHandler implements PrinterImpl {
//请求地址
@@ -62,12 +57,162 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
.setBr("<BR>")
.setBold(new String[]{"<B>", "</B>"});
@Override
protected void onlyKitchenPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
String buildDishPrintData = buildOnlyKitchenPrintData(getPickupNum(orderInfo), orderDetail);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
if (1 == machine.getVolumeSwitch()) {
voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
}
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(orderInfo.getId(), machine, "后厨商品单", buildDishPrintData, resp);
}
@Override
public OrderPrintDTO allKitchenPrint(OrderInfo orderInfo, List<OrderDetail> orderDetails, PrintMachine machine) {
OrderPrintDTO orderPrintDTO = super.allKitchenPrint(orderInfo, orderDetails, machine);
String buildDishPrintData = buildAllKitchenPrintData(orderPrintDTO, orderDetails);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
if (1 == machine.getVolumeSwitch()) {
voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
}
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(orderInfo.getId(), machine, "后厨总单", buildDishPrintData, resp);
return null;
}
@Override
public OrderPrintDTO returnKitchenPrint(String operator, OrderInfo orderInfo, List<OrderDetail> orderDetail, PrintMachine machine) {
OrderPrintDTO orderPrintDTO = super.returnKitchenPrint(operator, orderInfo, orderDetail, machine);
String buildDishPrintData = buildAllKitchenPrintData(orderPrintDTO, orderDetail);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
if (1 == machine.getVolumeSwitch()) {
voiceJson = "{\"bizType\":\"2\",\"content\":\"退菜消息,请及时处理\"}";
}
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(orderInfo.getId(), machine, "后厨退菜", buildDishPrintData, resp);
return null;
}
@Override
public OrderPrintDTO returnOrderPrint(String printTitle, String operator, String refundAmount, String refundReason, String refundType,
OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
OrderPrintDTO orderPrintDTO = super.returnOrderPrint(printTitle, operator, refundAmount, refundReason, refundType, orderInfo, machine, detailList);
String data = buildRefundOrderPrintData(orderPrintDTO, detailList);
sendOrderPrint(data, orderInfo.getId(), machine, "退款单");
return null;
}
@Override
public OrderPrintDTO guestOrderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
OrderPrintDTO orderPrintDTO = super.guestOrderPrint(orderInfo, machine, detailList);
String data = buildGuestOrderPrintData(orderPrintDTO, detailList);
sendOrderPrint(data, orderInfo.getId(), machine, "客看单");
return null;
}
@Override
public OrderPrintDTO preOrderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
OrderPrintDTO orderPrintDTO = super.preOrderPrint(orderInfo, machine, detailList);
String data = buildOrderPrintData(orderPrintDTO, detailList);
sendOrderPrint(data, orderInfo.getId(), machine, "预结算单");
return null;
}
@Override
public OrderPrintDTO orderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
OrderPrintDTO orderPrintDTO = super.orderPrint(orderInfo, machine, detailList);
String data = buildOrderPrintData(orderPrintDTO, detailList);
sendOrderPrint(data, orderInfo.getId(), machine, "结算单");
return null;
}
/**
* 叫号单打印
*/
@Override
protected void callNumPrint(PrintMachine machine, String callNum, String shopName, String tableName, String tableNote, String preNum, String codeUrl, LocalDateTime takeTime, String shopNote) {
String resp = buildCallTicketData(shopName, tableName, callNum, preNum, codeUrl, shopNote, takeTime);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
if (1 == machine.getVolumeSwitch()) {
voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一条新的排号记录\"}";
}
sendPrintRequest(machine.getAddress(), resp, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
}
@Override
protected void stockPrint(PrintMachine machine, String shopName, StockPrintDTO record) {
record.setShopName(shopName);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
String data = buildStockData(record);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(machine, "入库单", data, resp);
}
@Override
protected void dayReportPrint(PrintMachine machine, String shopName, DayReportPrintDTO record) {
record.setShopName(shopName);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
String data = buildDayReportData(record);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(machine, "经营日报单", data, resp);
}
@Override
protected void productReportPrint(PrintMachine machine, String shopName, ProductReportPrintDTO record) {
record.setShopName(shopName);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
String data = buildProductReportData(record);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(machine, "商品报表单", data, resp);
}
@Override
protected void rechargePrint(PrintMachine machine, String shopName, RechargePrintDTO record) {
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
record.setShopName(shopName);
String data = buildRechargeData(record);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(machine, "储值单", data, resp);
}
@Override
protected void stockCheckPrint(PrintMachine machine, String shopName, StockCheckPrintDTO record) {
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
record.setShopName(shopName);
String data = buildStockCheckData(record);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(machine, "盘点单", data, resp);
}
/**
* 交班单打印
*/
@Override
protected void handoverPrint(PrintMachine machine, String shopName, HandoverRecordDTO record) {
String string = buildHandoverData(record);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
sendPrintRequest(machine.getAddress(), string, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
}
private void sendOrderPrint(String data, Long orderId, PrintMachine machine, String bizType) {
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
if (1 == machine.getVolumeSwitch()) {
voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
}
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
printMachineLogService.save(orderId, machine, bizType, data, resp);
}
@Override
public PrintSignLabel getSignLabelInfo() {
return printSignLabel;
}
@Override
public String sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum) {
log.info("开始请求云享印,请求数据:{}, {}", voiceData, metaPrintData);
@@ -104,81 +249,6 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
return httpResponse;
}
@Override
protected void normalDishesPrint(String operator, OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
String buildDishPrintData = buildDishPrintData(false, getPickupNum(orderInfo), DateUtil.format(orderDetail.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), orderDetail.getProductName(), orderDetail.getSkuName(),
orderDetail.getNum(), orderDetail.getRemark(), orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
if (1 == machine.getVolumeSwitch()) {
voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
}
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
printMachineLogService.save(orderInfo.getId(), machine, "新订单", buildDishPrintData, resp);
}
@Override
protected void returnDishesPrint(String operator, OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
String buildDishPrintData = buildDishPrintData(true, getPickupNum(orderInfo), DateUtil.format(orderDetail.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), orderDetail.getProductName(), orderDetail.getSkuName(),
orderDetail.getReturnNum(), orderDetail.getRemark(), orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
printMachineLogService.save(orderInfo.getId(), machine, "退款单", buildDishPrintData, resp);
}
@Override
public PrintInfoDTO returnOrderPrint(String printTitle, String operator, String refundAmount, String refundReason, String refundType,
OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
PrintInfoDTO printInfoDTO = super.returnOrderPrint(printTitle, operator, refundAmount, refundReason, refundType, orderInfo, machine, detailList);
String data = buildRefundOrderPrintData(printInfoDTO, detailList);
sendOrderPrint(data, orderInfo.getId(), machine, "退款单");
return null;
}
@Override
public PrintInfoDTO guestOrderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
PrintInfoDTO printInfoDTO = super.guestOrderPrint(orderInfo, machine, detailList);
String data = buildGuestOrderPrintData(printInfoDTO, detailList);
sendOrderPrint(data, orderInfo.getId(), machine, "客看单");
return null;
}
@Override
public PrintInfoDTO preOrderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
PrintInfoDTO printInfoDTO = super.preOrderPrint(orderInfo, machine, detailList);
String data = buildOrderPrintData(printInfoDTO, detailList);
sendOrderPrint(data, orderInfo.getId(), machine, "预结算单");
return null;
}
@Override
public PrintInfoDTO orderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
PrintInfoDTO printInfoDTO = super.orderPrint(orderInfo, machine, detailList);
String data = buildOrderPrintData(printInfoDTO, detailList);
sendOrderPrint(data, orderInfo.getId(), machine, "结算单");
return null;
}
/**
* 叫号单打印
*/
@Override
protected void callNumPrint(PrintMachine machine, String callNum, String shopName, String tableName, String tableNote, String preNum, String codeUrl, LocalDateTime takeTime, String shopNote) {
String resp = buildCallTicketData(shopName, tableName, callNum, preNum, codeUrl, shopNote, takeTime);
sendPrintRequest(machine.getAddress(), resp, null, "1");
}
/**
* 交班单打印
*/
@Override
protected void handoverPrint(PrintMachine machine, HandoverRecordDTO record) {
String string = buildHandoverData(record);
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
sendPrintRequest(machine.getAddress(), string, voiceJson, "1");
}
/**
* 获取TOKEN值
@@ -202,20 +272,6 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
return SecureUtil.md5(token + APP_SECRET).toUpperCase();
}
private void sendOrderPrint(String data, Long orderId, PrintMachine machine, String bizType) {
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
if (1 == machine.getVolumeSwitch()) {
voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
}
String printerNum = "1";
if (StrUtil.isNotBlank(machine.getPrintQty())) {
printerNum = machine.getPrintQty().split("\\^")[1];
}
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, printerNum);
printMachineLogService.save(orderId, machine, bizType, data, resp);
}
/**
* 检查打印状态
*

View File

@@ -44,8 +44,12 @@ import com.czg.order.service.*;
import com.czg.order.vo.*;
import com.czg.pay.PayNotifyRespDTO;
import com.czg.product.entity.Product;
import com.czg.product.entity.ShopProdCategory;
import com.czg.product.service.ProductRpcService;
import com.czg.product.service.ProductService;
import com.czg.product.service.ShopProdCategoryService;
import com.czg.product.vo.ConsStockRecord;
import com.czg.product.vo.ProductStockVO;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
@@ -108,6 +112,8 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
@DubboReference
private ProductService productService;
@DubboReference
private ShopProdCategoryService shopProdCategoryService;
@DubboReference
private ProductRpcService productRpcService;
@DubboReference
private ShopInfoService shopInfoService;
@@ -326,11 +332,14 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
if ("after-pay".equals(orderInfo.getPayMode())) {
//
log.info("后付费生成订单{},第{}", orderInfo.getId(), orderInfo.getPlaceNum());
//客看单
printerHandler.orderHandler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.GUEST_ORDER, orderInfo.getPlaceNum());
//发送打票信息 后付费推送多次 需要处理
//orderId_0_0 订单ID_先付后付(1先付0后付)_订单状态 0未完成 1完成
//orderId_0_0 订单ID_先付后付(1先付0后付)_订单状态 0未完成 1完成_第几次下单
//orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_0"
rabbitPublisher.sendOrderPrintMsg(orderInfo.getId() + "_0_0", false, "后付费打印");
//后付费 菜品单
rabbitPublisher.sendKitchenOrderPrintMsg(orderInfo.getId() + "_0_0", false, "后付费打印");
// 消息通知 本地打印机执行
rabbitPublisher.sendOrderPrintMsg(orderInfo.getId() + "_0_0_" + orderInfo.getPlaceNum(), true, "后付费打印");
} else {
redisService.set(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId(), "", 60 * 15);
}
@@ -1038,15 +1047,13 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
*/
private void processOrderDetails(List<OrderDetail> orderDetails, LimitRateDTO limitRate, OrderInfoAddDTO param) throws CzgException {
BigDecimal packFee = BigDecimal.ZERO;
Map<Long, BigDecimal> productNumMap = new HashMap<>();
for (OrderDetail detail : orderDetails) {
if (!detail.getIsTemporary().equals(1) && detail.getProductId() > 0) {
Product product = productService.getOne(QueryWrapper.create()
.eq(Product::getId, detail.getProductId())
.eq(Product::getShopId, detail.getShopId())
.eq(Product::getIsDel, 0)
.eq(Product::getIsStock, 1));
if (product != null && detail.getNum().compareTo(new BigDecimal(product.getStockNumber())) > 0) {
throw new CzgException("下单失败" + product.getName() + "库存不足");
if (!detail.getIsTemporary().equals(1) && detail.getProductId() > 0 && 1 == detail.getIsAutoSoldStock()) {
if (productNumMap.containsKey(detail.getProductId())) {
productNumMap.put(detail.getProductId(), productNumMap.get(detail.getProductId()).add(detail.getNum().subtract(detail.getReturnNum())));
} else {
productNumMap.put(detail.getProductId(), detail.getNum().subtract(detail.getReturnNum()));
}
}
if (detail.getDiscountSaleAmount() != null && detail.getDiscountSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
@@ -1065,9 +1072,29 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
detail.setPayAmount(detail.getNum().multiply(detail.getUnitPrice()));
packFee = packFee.add(detail.getPackAmount().multiply(detail.getPackNumber()));
}
if (CollUtil.isNotEmpty(productNumMap)) {
checkStock(param.getShopId(), productNumMap);
}
param.setPackFee(packFee);
}
/**
* 校验库存数
*
* @param productNumMap 商品Id ,使用数量
*/
private void checkStock(Long shopId, Map<Long, BigDecimal> productNumMap) {
if (CollUtil.isEmpty(productNumMap)) {
return;
}
List<ConsStockRecord> consNumList = orderInfoCustomMapper.getConsByProductAndNum(shopId, productNumMap);
for (ConsStockRecord consStockRecord : consNumList) {
if (consStockRecord.getStockNumber().compareTo(consStockRecord.getCurrentStockNumber()) > 0) {
throw new CzgException("耗材:" + consStockRecord.getConName() + "库存不足,当前库存:" + consStockRecord.getCurrentStockNumber());
}
}
}
@Override
@Transactional
public void payCallBackOrder(@NotBlank String orderNo, @NotNull PayNotifyRespDTO notifyRespDTO, String channel, int retryCount) {
@@ -1275,6 +1302,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
if (payType != PayEnums.BACK_SCAN) {
// 事务成功提交后执行消息发送
String printParam = orderId + "_" + (!"after-pay".equals(payMode) ? 1 : 0) + "_1";
rabbitPublisher.sendKitchenOrderPrintMsg(printParam, isPrint, "事务环境打印");
rabbitPublisher.sendOrderPrintMsg(printParam, isPrint, "事务环境打印");
}
// log.info("订单{}事务提交后,发送打印消息", orderId);
@@ -1285,6 +1313,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
// 非事务环境下直接发送(兼容无事务场景)
String printParam = orderId + "_" + (!"after-pay".equals(payMode) ? 1 : 0) + "_1";
rabbitPublisher.sendOrderPrintMsg(printParam, isPrint, "非事务环境打印");
rabbitPublisher.sendKitchenOrderPrintMsg(printParam, isPrint, "非事务环境打印");
}
// log.info("非事务环境下,直接发送订单{}打印消息", orderId);
}
@@ -1448,7 +1477,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
}
if (table != null) {
orderInfo.setTableCode(table.getTableCode());
orderInfo.setTableName(table.getName());
orderInfo.setTableName(shopTableService.getTableAreaAndName(shopInfo.getId(), table.getTableCode(), table.getName()));
}
// 餐位费
if (shopInfo.getIsTableFee().equals(0)) {
@@ -1589,9 +1618,6 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
}
switch (orderInfoPrintDTO.getType()) {
case 0://菜品和结算单同时打印
printerHandler.orderHandler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.ONE_AND_ORDER, null);
break;
case 1://预结算单
printerHandler.orderHandler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.PRE_ORDER, null);
break;
@@ -1693,17 +1719,13 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
return true;
}
List<OrderDetail> details = orderDetailService.list(QueryWrapper.create().eq(OrderDetail::getOrderId, orderId).eq(OrderDetail::getPlaceNum, placeNum));
List<Map<String, Object>> dataList = new ArrayList<>();
List<ProductStockVO> listStock = new ArrayList<>();
for (OrderDetail detail : details) {
Map<String, Object> data = new HashMap<>();
data.put("shopId", shopId);
data.put("productId", detail.getProductId());
data.put("num", NumberUtil.sub(detail.getNum(), detail.getReturnNum()));
dataList.add(data);
listStock.add(new ProductStockVO(detail.getProductId(), NumberUtil.sub(detail.getNum(), detail.getReturnNum())));
}
orderDetailService.remove(new QueryWrapper().eq(OrderDetail::getOrderId, orderId).eq(OrderDetail::getPlaceNum, placeNum));
if (CollUtil.isNotEmpty(dataList)) {
productRpcService.orderCancelRecoverStock(shopId, orderId, dataList);
if (CollUtil.isNotEmpty(listStock)) {
productRpcService.orderCancelRecoverStock(shopId, orderId, listStock);
}
List<OrderDetail> list = orderDetailService.queryChain().eq(OrderDetail::getOrderId, orderId).eq(OrderDetail::getShopId, shopId).list();
if (CollUtil.isEmpty(list)) {
@@ -1829,4 +1851,48 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
rabbitPublisher.sendOrderDetailStatusMsg(shopId.toString(), "bc");
return true;
}
/**
* 退单库存问题
* 1退菜退库存 2仅退菜不退库存 3每次询问-退菜后弹窗提示1
*/
@Override
public void refundStock(ShopInfo shopInfo, Long orderId, Map<Long, BigDecimal> products, boolean refundStock) {
List<Product> list = productService.list(new QueryWrapper().select(Product::getId, Product::getCategoryId, Product::getRefundMode)
.eq(Product::getShopId, shopInfo.getId())
.in(Product::getId, products.keySet()));
if (CollUtil.isEmpty(list)) {
return;
}
List<ProductStockVO> resultProduct = new ArrayList<>();
HashMap<Long, Integer> categoryMap = new HashMap<>();
for (Product product : list) {
Integer refundMode;
if (shopInfo.getRefundMode().equals(1)) {
//分类
if (!categoryMap.containsKey(product.getCategoryId())) {
refundMode = shopProdCategoryService.getOneAs(new QueryWrapper().select(ShopProdCategory::getRefundMode)
.eq(ShopProdCategory::getShopId, shopInfo.getId()).eq(ShopProdCategory::getId, product.getCategoryId()), Integer.class);
categoryMap.put(product.getCategoryId(), refundMode);
} else {
refundMode = categoryMap.get(product.getCategoryId());
}
} else if (shopInfo.getRefundMode().equals(2)) {
//单商品
refundMode = product.getRefundMode();
} else {
log.error("退菜模式错误 店铺{},退款模式{},商品Id{}分类Id{}", shopInfo.getShopName(), shopInfo.getRefundMode(), product.getId(), product.getCategoryId());
throw new CzgException("退菜模式错误");
}
if (refundMode.equals(1)) {
resultProduct.add(new ProductStockVO(product.getId(), products.get(product.getId())));
} else if (refundMode.equals(3) && refundStock) {
resultProduct.add(new ProductStockVO(product.getId(), products.get(product.getId())));
}
}
if (CollUtil.isNotEmpty(resultProduct)) {
rabbitPublisher.sendOrderRefundMsg(JSONObject.toJSONString(Map.of("orderId", orderId, "returnProList", resultProduct)));
}
}
}

View File

@@ -1,9 +1,9 @@
package com.czg.service.order.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.entity.HandoverRecord;
import com.czg.account.vo.HandoverCategoryListVo;
import com.czg.account.vo.HandoverProductListVo;
import com.czg.config.RabbitPublisher;
@@ -12,8 +12,9 @@ import com.czg.order.entity.OrderDetail;
import com.czg.order.entity.OrderInfo;
import com.czg.order.service.OrderInfoRpcService;
import com.czg.product.service.ProductRpcService;
import com.czg.service.order.mapper.OrderDetailMapper;
import com.czg.product.vo.ProductStockVO;
import com.czg.service.market.mapper.OrderInfoMapper;
import com.czg.service.order.mapper.OrderDetailMapper;
import com.mybatisflex.core.query.QueryWrapper;
import io.seata.spring.annotation.GlobalTransactional;
import jakarta.annotation.Resource;
@@ -23,7 +24,8 @@ import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
/**
* 订单Rpc ServiceImpl
@@ -47,55 +49,6 @@ public class OrderInfoRpcServiceImpl implements OrderInfoRpcService {
@Resource
private RabbitPublisher rabbitPublisher;
@Override
public BigDecimal getHandoverWechatAmount(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.getHandoverWechatAmount(shopId, loginTime, handoverTime);
}
@Override
public BigDecimal getHandoverAlipayAmount(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.getHandoverAlipayAmount(shopId, loginTime, handoverTime);
}
@Override
public BigDecimal getHandoverVipPayAmount(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.getHandoverVipPayAmount(shopId, loginTime, handoverTime);
}
@Override
public BigDecimal getHandoverVipChargeAmount(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.getHandoverVipChargeAmount(shopId, loginTime, handoverTime);
}
@Override
public BigDecimal getHandoverQuickPayAmount(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.getHandoverQuickPayAmount(shopId, loginTime, handoverTime);
}
@Override
public BigDecimal getHandoverCashAmount(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.getHandoverCashAmount(shopId, loginTime, handoverTime);
}
@Override
public BigDecimal getHandoverRefundAmount(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.getHandoverRefundAmount(shopId, loginTime, handoverTime);
}
@Override
public BigDecimal getHandoverCreditAmount(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.getHandoverCreditAmount(shopId, loginTime, handoverTime);
}
@Override
public BigDecimal getHandoverTotalAmount(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.getHandoverTotalAmount(shopId, loginTime, handoverTime);
}
@Override
public int getHandoverOrderNum(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.getHandoverOrderNum(shopId, loginTime, handoverTime);
}
@Override
public List<HandoverProductListVo> getHandoverDetailList(Long shopId, String loginTime, String handoverTime) {
@@ -107,6 +60,22 @@ public class OrderInfoRpcServiceImpl implements OrderInfoRpcService {
return orderInfoMapper.getHandoverCategoryList(shopId, loginTime, handoverTime);
}
@Override
public HandoverRecord getOnlinePayTypeDate(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.getOnlinePayTypeDate(shopId, loginTime, handoverTime);
}
@Override
public BigDecimal countReturnDish(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.countReturnDish(shopId, loginTime, handoverTime);
}
@Override
public HandoverRecord countShopUserFlow(Long shopId, String loginTime, String handoverTime) {
return orderInfoMapper.countShopUserFlow(shopId, loginTime, handoverTime);
}
@Override
@GlobalTransactional
public void paySuccessCallback(Long orderId) {
@@ -127,16 +96,12 @@ public class OrderInfoRpcServiceImpl implements OrderInfoRpcService {
}
Long shopId = orderInfo.getShopId();
// 封装扣减库存数据
List<Map<String, Object>> dataList = new ArrayList<>();
List<ProductStockVO> dataList = new ArrayList<>();
for (OrderDetail orderDetail : detailList) {
Map<String, Object> data = new HashMap<>(16);
Long productId = orderDetail.getProductId();
BigDecimal num = orderDetail.getNum();
BigDecimal refundNum = orderDetail.getRefundNum();
data.put("shopId", shopId);
data.put("productId", productId);
data.put("num", NumberUtil.sub(num, refundNum));
dataList.add(data);
dataList.add(new ProductStockVO(productId, NumberUtil.sub(num, refundNum)));
}
try {
// 调用商品服务扣减库存
@@ -162,22 +127,18 @@ public class OrderInfoRpcServiceImpl implements OrderInfoRpcService {
if (CollUtil.isEmpty(detailList)) {
throw new CzgException("该订单下不存在商品");
}
Long shopId = orderInfo.getShopId();
// 封装扣减库存数据
List<Map<String, Object>> dataList = new ArrayList<>();
List<ProductStockVO> dataList = new ArrayList<>();
for (OrderDetail orderDetail : detailList) {
Map<String, Object> data = new HashMap<>(16);
Long productId = orderDetail.getProductId();
BigDecimal num = orderDetail.getNum();
BigDecimal refundNum = orderDetail.getRefundNum();
data.put("shopId", shopId);
data.put("productId", productId);
data.put("num", NumberUtil.sub(num, refundNum));
dataList.add(data);
BigDecimal returnNum = orderDetail.getReturnNum();
dataList.add(new ProductStockVO(productId, NumberUtil.sub(num, refundNum, returnNum)));
}
try {
// 调用商品服务扣减库存
productRpcService.orderCancelRecoverStock(shopId, orderId, dataList);
productRpcService.orderCancelRecoverStock(orderInfo.getShopId(), orderId, dataList);
} catch (Exception e) {
log.error("调用商品服务恢复库存", e);
throw e;
@@ -186,7 +147,6 @@ public class OrderInfoRpcServiceImpl implements OrderInfoRpcService {
@Override
public void orderRefundCallback(JSONObject data) {
log.info(">>>>>>>>>>>>>>>>>:入参:{}", data.toJSONString());
Long orderId = data.getLong("orderId");
// 订单取消后商品库存恢复,耗材恢复,流水记录
OrderInfo orderInfo = orderInfoMapper.selectOneById(orderId);
@@ -198,19 +158,7 @@ public class OrderInfoRpcServiceImpl implements OrderInfoRpcService {
if (CollUtil.isEmpty(detailList)) {
throw new CzgException("该订单下不存在商品");
}
JSONObject obj = data.getJSONObject("returnProMap");
Set<String> keys = obj.keySet();
// 封装扣减库存数据
List<Map<String, Object>> dataList = new ArrayList<>();
for (String key : keys) {
Long productId = Convert.toLong(key);
BigDecimal num = obj.getBigDecimal(key);
Map<String, Object> row = new HashMap<>(3);
row.put("shopId", orderInfo.getShopId());
row.put("productId", productId);
row.put("num", num);
dataList.add(row);
}
List<ProductStockVO> dataList = data.getList("returnProList", ProductStockVO.class);
try {
// 调用商品服务回退库存
productRpcService.orderRefundReturnStock(orderInfo.getShopId(), orderId, dataList);
@@ -221,7 +169,8 @@ public class OrderInfoRpcServiceImpl implements OrderInfoRpcService {
}
@Override
public void sendHandoverReceiptPrintMsgToMq(Long handoverRecordId) {
rabbitPublisher.sendHandoverPrintMsg(Convert.toStr(handoverRecordId));
public void sendHandoverReceiptPrintMsgToMq(Long shopId, HandoverRecord record) {
rabbitPublisher.sendOtherPrintMsg(shopId, record, "HANDOVER");
}
}

View File

@@ -1,13 +1,11 @@
package com.czg.service.order.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson2.JSONObject;
import com.czg.PayCst;
import com.czg.account.dto.shopuser.ShopUserMoneyEditDTO;
import com.czg.account.entity.ShopInfo;
@@ -118,6 +116,8 @@ public class OrderPayServiceImpl implements OrderPayService {
//发送打票信息
//orderId_0_0 订单ID_先付后付(1先付0后付)_订单状态 0未完成 1完成
//orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_0"
rabbitPublisher.sendKitchenOrderPrintMsg(orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_1",
orderInfo.getIsPrint() == 1, "0元付款");
rabbitPublisher.sendOrderPrintMsg(orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_1",
orderInfo.getIsPrint() == 1, "0元付款");
redisService.del(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId());
@@ -362,6 +362,7 @@ public class OrderPayServiceImpl implements OrderPayService {
LocalDateTime.now(), paymentId, PayEnums.BACK_SCAN);
// 事务成功提交后执行消息发送
String printParam = orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_1";
rabbitPublisher.sendKitchenOrderPrintMsg(printParam, orderInfo.getIsPrint() == 1, "事务环境打印");
rabbitPublisher.sendOrderPrintMsg(printParam, orderInfo.getIsPrint() == 1, "事务环境打印");
} else {
upOrderPayInfo(orderInfo.getId(), PayEnums.BACK_SCAN, paymentId,
@@ -380,7 +381,7 @@ public class OrderPayServiceImpl implements OrderPayService {
}
boolean isFirstRefund = orderInfo.getRefundAmount().compareTo(BigDecimal.ZERO) == 0;
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
Map<String, BigDecimal> returnProMap = new HashMap<>();
Map<Long, BigDecimal> productStockMap = new HashMap<>();
boolean isPay = true;
String refPayOrderNo = "REFO" + IdUtil.getSnowflakeNextId();
if (orderInfo.getStatus().equals(OrderStatusEnums.UNPAID.getCode())) {
@@ -440,7 +441,11 @@ public class OrderPayServiceImpl implements OrderPayService {
}
orderDetailService.updateById(orderDetail);
if (orderDetail.getProductId() != null && orderDetail.getProductId() > 0) {
returnProMap.put(Convert.toStr(orderDetail.getProductId()), refundDetail.getNum());
if (productStockMap.containsKey(orderDetail.getProductId())) {
productStockMap.put(orderDetail.getProductId(), productStockMap.get(orderDetail.getProductId()).add(refundDetail.getNum()));
} else {
productStockMap.put(orderDetail.getProductId(), refundDetail.getNum());
}
}
}
long count = orderDetailService.count(QueryWrapper.create().eq(OrderDetail::getOrderId, orderInfo.getId())
@@ -458,14 +463,22 @@ public class OrderPayServiceImpl implements OrderPayService {
for (OrderDetail orderDetail : orderDetails) {
if (isPay) {
if (orderDetail.getProductId() != null && orderDetail.getProductId() > 0) {
returnProMap.put(Convert.toStr(orderDetail.getProductId()), orderDetail.getNum().subtract(orderDetail.getReturnNum()).subtract(orderDetail.getRefundNum()));
if (productStockMap.containsKey(orderDetail.getProductId())) {
productStockMap.put(orderDetail.getProductId(), productStockMap.get(orderDetail.getProductId()).add(orderDetail.getNum().subtract(orderDetail.getReturnNum()).subtract(orderDetail.getRefundNum())));
} else {
productStockMap.put(orderDetail.getProductId(), orderDetail.getNum().subtract(orderDetail.getReturnNum()).subtract(orderDetail.getRefundNum()));
}
}
orderDetail.setReturnAmount(orderDetail.getPayAmount());
orderDetail.setRefundNum(orderDetail.getNum().subtract(orderDetail.getReturnNum()));
orderDetail.setStatus(OrderStatusEnums.REFUND.getCode());
} else {
if (orderDetail.getProductId() != null && orderDetail.getProductId() > 0) {
returnProMap.put(Convert.toStr(orderDetail.getProductId()), orderDetail.getNum().subtract(orderDetail.getReturnNum()));
if (productStockMap.containsKey(orderDetail.getProductId())) {
productStockMap.put(orderDetail.getProductId(), productStockMap.get(orderDetail.getProductId()).add(orderDetail.getNum().subtract(orderDetail.getReturnNum())));
} else {
productStockMap.put(orderDetail.getProductId(), orderDetail.getNum().subtract(orderDetail.getReturnNum()));
}
}
orderDetail.setReturnNum(orderDetail.getNum());
orderDetail.setStatus(OrderStatusEnums.CANCELLED.getCode());
@@ -510,12 +523,21 @@ public class OrderPayServiceImpl implements OrderPayService {
orderInfo.setRefundRemark(orderInfo.getRefundRemark() + param.getRefundReason());
orderInfoService.updateById(orderInfo);
//退款后续 退款单/退菜单
printerHandler.refundOrderHandler(printTitle, StrUtil.isNotBlank(param.getOperator()) ? param.getOperator() : ""
, isPay ? param.getRefundAmount().toPlainString() : "0"
, param.getRefundReason(), orderInfo.getRefundType(), orderInfo, param.getRefundDetails());
if (param.isPrint()) {
String finalPrintTitle = printTitle;
boolean finalIsPay = isPay;
FunUtils.safeRunVoid(() -> printerHandler.refundOrderHandler(finalPrintTitle, StrUtil.isNotBlank(param.getOperator()) ? param.getOperator() : ""
, finalIsPay ? param.getRefundAmount().toPlainString() : "0"
, param.getRefundReason(), orderInfo.getRefundType(), orderInfo, param.getRefundDetails()),
"订单id:{} 退款,前台打印消息失败", orderInfo.getId());
}
//后厨退菜单
FunUtils.safeRunVoid(() -> printerHandler.kitchenRefundAllHandler(StrUtil.isNotBlank(param.getOperator()) ? param.getOperator() : "", orderInfo, param.getRefundDetails()),
"订单id:{} 退款,后厨退菜单打印消息失败", orderInfo.getId());
//退款返还库存
if (!returnProMap.isEmpty()) {
rabbitPublisher.sendOrderRefundMsg(JSONObject.toJSONString(Map.of("orderId", orderInfo.getId(), "returnProMap", returnProMap)));
if (!productStockMap.isEmpty()) {
FunUtils.safeRunVoid(() -> orderInfoCustomService.refundStock(shopInfo, orderInfo.getId(), productStockMap, param.isRefundStock()),
"订单id:{} 退款,库存处理失败", orderInfo.getId());
}
refundOrderAfter(orderInfo.getId(), orderInfo.getShopId(), orderInfo.getUserId(), orderInfo.getOrderNo(),
orderInfo.getPointsNum(), isFirstRefund, orderInfo.getStatus().equals(OrderStatusEnums.REFUND.getCode()));

View File

@@ -93,7 +93,7 @@ public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMappe
String respMsg = "打印中";
JSONObject resp = JSONObject.parseObject(respJson);
// 云想印
if ("云想印".equals(config.getContentType())) {
if ("云想印".equals(config.getBrand())) {
int code = resp.getIntValue("code");
JSONObject respData = resp.getJSONObject("data");
JSONObject data = respData.getJSONObject("data");
@@ -112,7 +112,7 @@ public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMappe
entity.setTaskId(respData.getString("orderId"));
}
// 飞鹅云打印机暂时没有适配先return不做打印记录
} else if ("飞鹅".equals(config.getContentType())) {
} else if ("飞鹅".equals(config.getBrand())) {
int ret = resp.getIntValue("ret");
if (ret != 0) {
failFlag = 1;
@@ -170,7 +170,7 @@ public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMappe
try {
// 1. 云想印打印机状态查询
if ("云想印".equals(config.getContentType())) {
if ("云想印".equals(config.getBrand())) {
String jsonStr = yxyPrinter.checkPrintStatus(config.getAddress(), entity.getTaskId());
log.info("云想印打印状态查询结果(第{}次,虚拟线程:{}{}",
currentTimes, Thread.currentThread().getName(), jsonStr);
@@ -185,7 +185,7 @@ public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMappe
}
}
// 2. 飞鹅云打印机状态查询
else if ("飞鹅".equals(config.getContentType())) {
else if ("飞鹅".equals(config.getBrand())) {
Boolean success = feiPrinter.checkFPrintStatus(entity.getTaskId());
if (success == null) {
entity.setFailFlag(1);

View File

@@ -19,6 +19,7 @@
cart.product_id as productId,
pros.cover_img as productImg,
pros.type as productType,
pros.is_auto_sold_stock as isAutoSoldStock,
cart.sku_id as skuId,
cart.is_time_discount as isTimeDiscount,
skus.spec_info as skuName,

View File

@@ -45,39 +45,6 @@
where id = #{orderId};
</update>
<select id="getHandoverCashAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
and t1.pay_type = 'cash_pay'
</where>
</select>
<select id="getHandoverRefundAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.refund_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
</where>
</select>
<select id="getHandoverTotalAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
</where>
</select>
<select id="getHandoverOrderNum" resultType="java.lang.Integer">
SELECT
count(*)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
</where>
</select>
<select id="getHandoverDetailList" resultType="com.czg.account.vo.HandoverProductListVo">
SELECT
t2.product_id,
@@ -96,53 +63,7 @@
t2.product_id,
t2.sku_id
</select>
<select id="getHandoverWechatAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
and t1.pay_type = 'wechat_mini'
</where>
</select>
<select id="getHandoverAlipayAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
and t1.pay_type = 'alipay_mini'
</where>
</select>
<select id="getHandoverVipPayAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
and t1.pay_type = 'vip_pay'
</where>
</select>
<select id="getHandoverVipChargeAmount" resultType="java.math.BigDecimal">
select ifnull(sum(t1.amount), 0)
from tb_shop_user_flow t1
where t1.shop_id = #{shopId}
and t1.biz_code in ('cashIn', 'wechatIn', 'alipayIn', 'adminIn')
and t1.recharge_id is not null
<![CDATA[
AND t1.create_time >= str_to_date(#{loginTime}, '%Y-%m-%d %H:%i:%s')
AND t1.create_time <= str_to_date(#{handoverTime}, '%Y-%m-%d %H:%i:%s')
]]>
</select>
<select id="getHandoverQuickPayAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
and t1.pay_type in ('main_scan','back_scan')
</where>
</select>
<select id="getHandoverCategoryList" resultType="com.czg.account.vo.HandoverCategoryListVo">
SELECT case when t3.category_id is null then 0 else t3.category_id end as category_id,
case when t4.name is null then '未分类' else t4.name end as category_name,
@@ -158,14 +79,26 @@
</where>
GROUP BY t3.category_id
</select>
<select id="getHandoverCreditAmount" resultType="java.math.BigDecimal">
SELECT
ifnull(sum(t1.pay_amount),0)
FROM tb_order_info t1
<where>
<include refid="handoverCommonWhere"/>
and t1.pay_type = 'credit_pay'
</where>
</select>
<select id="getConsByProductAndNum" resultType="com.czg.product.vo.ConsStockRecord">
SELECT
r.cons_info_id AS consId,
SUM(r.surplus_stock *
CASE
<foreach collection="productUsageMap.entrySet()" item="qty" index="pid">
WHEN r.product_id = #{pid} THEN #{qty}
</foreach>
ELSE 0
END
) AS stockNumber,
cons.con_name as conName,
cons.stock_number as currentStockNumber
FROM tb_prod_cons_relation r INNER JOIN tb_cons_info cons on r.cons_info_id = cons.id and cons.is_stock = 1
WHERE r.shop_id = #{shopId} AND r.product_id IN
<foreach collection="productUsageMap.keySet()" item="pid" open="(" separator="," close=")">
#{pid}
</foreach>
GROUP BY r.cons_info_id
</select>
</mapper>

View File

@@ -21,4 +21,6 @@ public interface ProdConsRelationMapper extends BaseMapper<ProdConsRelation> {
List<ProductBriefDTO> getProductListByConId(@Param("conId") Long conId);
List<ProdConsRelationDTO> selectListByProdId(@Param("prodId") Long prodId);
List<ProdConsRelationDTO> selectStockByProdId(@Param("prodId") Long prodId);
}

View File

@@ -12,7 +12,6 @@ import com.mybatisflex.core.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.List;
/**
@@ -38,8 +37,6 @@ public interface ProductMapper extends BaseMapper<Product> {
List<RecommendProVO> selectCouponProBySaleNum();
void updateProductStockNum(@Param("id") Long id, @Param("shopId") Long shopId, @Param("type") String type, @Param("num") BigDecimal num);
List<RecommendProVO> selectRecommendProductList(@Param("lng") String lng, @Param("lat") String lat, @Param("address") String address,
@Param("classify") Integer classify, @Param("orderType") Integer orderType,
@Param("distanceType") Integer distanceType, @Param("name") String name);

View File

@@ -15,6 +15,7 @@ import com.czg.product.param.ConsInfoParam;
import com.czg.product.param.ConsSubUnitParam;
import com.czg.product.service.ConsInfoService;
import com.czg.product.vo.ConsStatisticsVo;
import com.czg.product.vo.ConsStockRecord;
import com.czg.sa.StpKit;
import com.czg.service.product.mapper.ConsGroupMapper;
import com.czg.service.product.mapper.ConsInfoMapper;
@@ -26,7 +27,7 @@ import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
@@ -40,7 +41,7 @@ import java.util.stream.Collectors;
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-02-20
*/
@Service
@DubboService
@AllArgsConstructor
public class ConsInfoServiceImpl extends ServiceImpl<ConsInfoMapper, ConsInfo> implements ConsInfoService {
@@ -99,6 +100,11 @@ public class ConsInfoServiceImpl extends ServiceImpl<ConsInfoMapper, ConsInfo> i
return list;
}
@Override
public List<ConsStockRecord> getConsStockList(Long shopId) {
return listAs(query().eq(ConsInfo::getShopId, shopId).eq(ConsInfo::getIsStock, SystemConstants.OneZero.ONE), ConsStockRecord.class);
}
@Override
public ConsInfoDTO getConsInfoById(Long id) {
Long shopId = StpKit.USER.getShopId(0L);
@@ -176,13 +182,6 @@ public class ConsInfoServiceImpl extends ServiceImpl<ConsInfoMapper, ConsInfo> i
super.updateById(entity);
}
@Override
public void isRefundStockConsInfo(Long id, Integer isRefundStock) {
Long shopId = StpKit.USER.getShopId();
ConsInfo entity = super.getOne(query().eq(ConsInfo::getId, id).eq(ConsInfo::getShopId, shopId));
entity.setIsRefundStock(isRefundStock);
super.updateById(entity);
}
@Override
public void modifySubUnit(ConsSubUnitParam param) {

View File

@@ -3,11 +3,15 @@ package com.czg.service.product.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.czg.config.RabbitPublisher;
import com.czg.exception.CzgException;
import com.czg.print.StockCheckPrintDTO;
import com.czg.print.StockPrintDTO;
import com.czg.product.dto.ConsStockFlowDTO;
import com.czg.product.entity.ConsInfo;
import com.czg.product.entity.ConsStockFlow;
@@ -21,6 +25,7 @@ import com.czg.service.product.mapper.ConsInfoMapper;
import com.czg.service.product.mapper.ConsStockFlowMapper;
import com.czg.service.product.mapper.ProductMapper;
import com.czg.service.product.util.WxAccountUtil;
import com.czg.utils.FunUtils;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@@ -34,6 +39,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@@ -52,6 +58,8 @@ public class ConsStockFlowServiceImpl extends ServiceImpl<ConsStockFlowMapper, C
private final ProductMapper productMapper;
@Resource
private WxAccountUtil wxAccountUtil;
@Resource
private RabbitPublisher rabbitPublisher;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -104,7 +112,7 @@ public class ConsStockFlowServiceImpl extends ServiceImpl<ConsStockFlowMapper, C
for (ConsInfo consInfo : updateStockList) {
consInfoMapper.update(consInfo);
}
FunUtils.transactionSafeRun(() -> sendInOutPrintMsg("IN", shopId, param));
return param;
}
@@ -141,6 +149,33 @@ public class ConsStockFlowServiceImpl extends ServiceImpl<ConsStockFlowMapper, C
for (ConsInfo consInfo : updateStockList) {
consInfoMapper.update(consInfo);
}
FunUtils.transactionSafeRun(() -> sendInOutPrintMsg("OUT", shopId, param));
}
private void sendInOutPrintMsg(String type, Long shopId, ConsInOutStockHeadParam param) {
StockPrintDTO stockPrint = new StockPrintDTO();
stockPrint.setType(type);
stockPrint.setPrintTime(LocalDateTime.now());
stockPrint.setOperator(param.getOperator());
stockPrint.setConsCount(param.getBodyList().size());
List<StockPrintDTO.InStockItem> items = new ArrayList<>();
BigDecimal totalInOutNumber = BigDecimal.ZERO;
BigDecimal totalAmount = BigDecimal.ZERO;
for (ConsInOutStockBodyParam cons : param.getBodyList()) {
StockPrintDTO.InStockItem item = new StockPrintDTO.InStockItem();
item.setConsName(cons.getConName());
item.setUnit(cons.getUnitName());
item.setStockNumber(cons.getInOutNumber());
item.setAmount(cons.getSubTotal());
items.add(item);
totalInOutNumber = NumberUtil.add(totalInOutNumber, cons.getInOutNumber());
totalAmount = NumberUtil.add(totalAmount, cons.getSubTotal());
}
stockPrint.setStockNumberCount(totalInOutNumber);
stockPrint.setAmountCount(totalAmount);
stockPrint.setItems(items);
//库存盘点
rabbitPublisher.sendOtherPrintMsg(shopId, stockPrint, "STOCK");
}
@Override
@@ -176,9 +211,22 @@ public class ConsStockFlowServiceImpl extends ServiceImpl<ConsStockFlowMapper, C
}
entity.setSubTotal(NumberUtil.mul(winLossNumber, param.getPrice()));
entity.setRemark(param.getRemark());
saveFlow(entity);
consInfo.setStockNumber(entity.getAfterNumber());
consInfoMapper.update(consInfo);
saveFlow(entity, consInfo.getConWarning());
FunUtils.transactionSafeRun(() -> {
StockCheckPrintDTO stockCheckPrintDTO = new StockCheckPrintDTO();
stockCheckPrintDTO.setWinLossNumberCount(winLossNumber.intValue());
stockCheckPrintDTO.setWinLossAmount(entity.getSubTotal());
stockCheckPrintDTO.setRemark(entity.getRemark());
stockCheckPrintDTO.setOperator(param.getOperator());
List<StockCheckPrintDTO.StockCheckItem> items = new ArrayList<>();
items.add(new StockCheckPrintDTO.StockCheckItem(consInfo.getConName(), param.getPrice(), consInfo.getConUnit(), param.getActualNumber(), param.getWinLossNumber()));
stockCheckPrintDTO.setItems(items);
//库存盘点
rabbitPublisher.sendOtherPrintMsg(shopId, stockCheckPrintDTO, "STOCK_CHECK");
});
}
@Override
@@ -220,9 +268,9 @@ public class ConsStockFlowServiceImpl extends ServiceImpl<ConsStockFlowMapper, C
entity.setInOutItem(InOutItemEnum.DAMAGE_OUT.value());
entity.setSubTotal(NumberUtil.mul(param.getNumber(), consInfo.getPrice()));
entity.setImgUrls(JSON.toJSONString(param.getImgUrls()));
saveFlow(entity);
consInfo.setStockNumber(entity.getAfterNumber());
consInfoMapper.update(consInfo);
saveFlow(entity, consInfo.getConWarning());
}
@Override
@@ -233,22 +281,29 @@ public class ConsStockFlowServiceImpl extends ServiceImpl<ConsStockFlowMapper, C
}
@Override
public void saveFlow(ConsStockFlow entity) {
public void saveFlow(ConsStockFlow entity, BigDecimal conWarning) {
super.save(entity);
Long shopId = entity.getShopId();
BigDecimal afterNumber = entity.getAfterNumber();
ConsInfo consInfo = consInfoMapper.selectOneById(entity.getConId());
String shopName = productMapper.getShopName(shopId);
BigDecimal conWarning = consInfo.getConWarning();
// 库存小于警告值,发送消息提醒
if (NumberUtil.isLess(afterNumber, conWarning)) {
List<String> openIdList = consInfoMapper.findOpenIdList(shopId, "con");
if (CollUtil.isEmpty(openIdList)) {
return;
}
String conName = StrUtil.format("{}数量<预警值{}", consInfo.getConName(), conWarning);
ThreadUtil.execAsync(() -> openIdList.parallelStream().forEach(openId ->
wxAccountUtil.sendStockMsg("耗材库存预警", shopName, conName, afterNumber, openId)));
boolean b = sendStockMsg(entity, conWarning);
if (b) {
ThreadUtil.execAsync(() -> rabbitPublisher.sendConsInfoChangeMsg(Convert.toStr(entity.getShopId())));
}
}
@Override
public boolean sendStockMsg(ConsStockFlow entity, BigDecimal warning) {
boolean result = false;
// 库存小于警告值,发送消息提醒
if (NumberUtil.isLess(entity.getAfterNumber(), warning)) {
result = true;
List<String> openIdList = consInfoMapper.findOpenIdList(entity.getShopId(), "con");
if (CollUtil.isEmpty(openIdList)) {
return result;
}
String shopName = productMapper.getShopName(entity.getShopId());
String conName = StrUtil.format("{}数量<预警值{}", entity.getConName(), warning);
ThreadUtil.execAsync(() -> openIdList.parallelStream().forEach(openId ->
wxAccountUtil.sendStockMsg("耗材库存预警", shopName, conName, entity.getAfterNumber(), openId)));
}
return result;
}
}

View File

@@ -63,6 +63,7 @@ public class ProdConsRelationServiceImpl extends ServiceImpl<ProdConsRelationMap
List<ProdConsRelationDTO> consList = dto.getConsList();
for (ProdConsRelationDTO con : consList) {
con.setShopId(shopId);
con.setProductId(dto.getId());
}
List<Long> list = consList.stream().map(ProdConsRelationDTO::getProductId).distinct().toList();
if (CollUtil.isNotEmpty(list) && list.size() > 1) {
@@ -75,4 +76,19 @@ public class ProdConsRelationServiceImpl extends ServiceImpl<ProdConsRelationMap
mapper.insertBatchSelective(entityList, 50);
}
@Override
public List<ProdConsRelationDTO> selectListByProdId(Long prodId) {
return mapper.selectListByProdId(prodId);
}
/**
* 扣减库存 使用
* @param prodId
* @return
*/
@Override
public List<ProdConsRelationDTO> selectStockByProdId(Long prodId) {
return mapper.selectStockByProdId(prodId);
}
}

View File

@@ -1,39 +1,21 @@
package com.czg.service.product.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.config.RabbitPublisher;
import com.czg.constants.SystemConstants;
import com.czg.product.dto.ProductStockSubtractDTO;
import com.czg.product.entity.*;
import com.czg.product.enums.InOutItemEnum;
import com.czg.product.enums.InOutTypeEnum;
import com.czg.product.service.ConsStockFlowService;
import com.czg.product.service.ProductRpcService;
import com.czg.product.service.ProductStockFlowService;
import com.czg.product.service.ProductService;
import com.czg.product.vo.ProductStockVO;
import com.czg.product.vo.ProductVO;
import com.czg.service.RedisService;
import com.czg.service.product.mapper.ConsInfoMapper;
import com.czg.service.product.mapper.ProdConsRelationMapper;
import com.czg.service.product.mapper.ProductMapper;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import static com.czg.constant.CacheConstant.ADMIN_CLIENT_PRODUCT_LIST;
import static com.czg.constant.CacheConstant.SHOP_PRODUCT_STOCK;
/**
* 商品RPC远程调用服务接口实现
@@ -47,273 +29,28 @@ public class ProductRpcServiceImpl implements ProductRpcService {
@Resource
private ProductMapper productMapper;
@Resource
private ProdConsRelationMapper prodConsRelationMapper;
@Resource
private ConsInfoMapper consInfoMapper;
@Resource
private ConsStockFlowService consStockFlowService;
@Resource
private ProductStockFlowService productStockFlowService;
@Resource
private RabbitPublisher rabbitPublisher;
private ProductService productService;
@Resource
private RedisService redisService;
@Override
@Transactional(rollbackFor = Exception.class)
//@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT, ADMIN_CLIENT_PRODUCT_LIST}, key = "#shopId", allEntries = true, beforeInvocation = true)
public void paySuccessSubtractStock(Long shopId, Long orderId, List<Map<String, Object>> dataList) {
List<ProductStockSubtractDTO> list = BeanUtil.copyToList(dataList, ProductStockSubtractDTO.class);
if (CollUtil.isEmpty(list)) {
return;
}
boolean isLowWarnLine = false;
for (ProductStockSubtractDTO dto : list) {
Product product = productMapper.selectOneById(dto.getProductId());
if (product == null) {
continue;
}
// 商品开启库存
if (product.getIsStock() == SystemConstants.OneZero.ONE) {
productMapper.updateProductStockNum(dto.getProductId(), dto.getShopId(), "sub", dto.getNum());
// 记录商品库存流水
ProductStockFlow flow = new ProductStockFlow();
flow.setCreateUserId(1L);
flow.setCreateUserName("银收客");
flow.setShopId(shopId);
flow.setProductId(product.getId());
flow.setProductName(product.getName());
flow.setBeforeNumber(NumberUtil.toBigDecimal(product.getStockNumber()));
flow.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, NumberUtil.toBigDecimal(dto.getNum())));
flow.setAfterNumber(NumberUtil.sub(NumberUtil.toBigDecimal(product.getStockNumber()), NumberUtil.toBigDecimal(dto.getNum())));
flow.setInOutType(InOutTypeEnum.OUT.value());
flow.setInOutItem(InOutItemEnum.ORDER_OUT.value());
flow.setOrderId(orderId);
productStockFlowService.saveFlow(flow);
cleanCategoryProduct(shopId, product.getCategoryId());
refreshRedisProdStock(shopId, product.getId(), flow.getAfterNumber());
Integer warnLine = ObjUtil.defaultIfNull(product.getWarnLine(), 10);
if (!isLowWarnLine && NumberUtil.isLess(flow.getAfterNumber(), Convert.toBigDecimal(warnLine))) {
isLowWarnLine = true;
}
}
public void paySuccessSubtractStock(Long shopId, Long orderId, List<ProductStockVO> list) {
productService.consStockByProduct(shopId, InOutTypeEnum.OUT, InOutItemEnum.ORDER_OUT, list, orderId, "订单消费");
// 查询商品绑定耗材信息
List<ProdConsRelation> relationList = prodConsRelationMapper.selectListByQuery(QueryWrapper.create().eq(ProdConsRelation::getProductId, dto.getProductId()));
if (CollUtil.isEmpty(relationList)) {
continue;
}
for (ProdConsRelation prodConsRelation : relationList) {
// 耗材id
Long consInfoId = prodConsRelation.getConsInfoId();
// 耗材消耗数量
BigDecimal surplusStock = prodConsRelation.getSurplusStock();
if (surplusStock == null || surplusStock.compareTo(BigDecimal.ZERO) == 0) {
continue;
}
// 实际消耗数量 = 耗材消耗数量 * 商品购买数量
surplusStock = NumberUtil.mul(surplusStock, dto.getNum());
ConsInfo consInfo = consInfoMapper.selectOneById(consInfoId);
if (consInfo == null || consInfo.getIsStock() == SystemConstants.OneZero.ZERO) {
continue;
}
BigDecimal stockNumber = consInfo.getStockNumber();
consInfo.setStockNumber(NumberUtil.sub(stockNumber, surplusStock));
// 更新耗材库存数量
consInfoMapper.update(consInfo);
// 插入耗材流水记录
ConsStockFlow consStockFlow = new ConsStockFlow();
consStockFlow.setShopId(shopId);
consStockFlow.setVendorId(null);
consStockFlow.setInOutType(InOutTypeEnum.OUT.value());
consStockFlow.setInOutItem(InOutItemEnum.ORDER_OUT.value());
consStockFlow.setInOutDate(LocalDate.now());
consStockFlow.setConId(consInfo.getId());
consStockFlow.setConName(consInfo.getConName());
consStockFlow.setUnitName(consInfo.getConUnit());
consStockFlow.setBeforeNumber(stockNumber);
consStockFlow.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, surplusStock));
consStockFlow.setAfterNumber(consInfo.getStockNumber());
consStockFlow.setSubTotal(NumberUtil.mul(surplusStock, consInfo.getPrice()));
consStockFlow.setProductId(dto.getProductId());
//consStockFlow.setSkuId(0L);
consStockFlow.setOrderId(orderId);
consStockFlowService.saveFlow(consStockFlow);
}
}
if (isLowWarnLine) {
ThreadUtil.execAsync(() -> rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId)));
}
log.info("ProductService.--------------------------------------------库存更新成功");
}
@Override
@Transactional(rollbackFor = Exception.class)
//@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT, ADMIN_CLIENT_PRODUCT_LIST}, key = "#shopId", allEntries = true, beforeInvocation = true)
public void orderCancelRecoverStock(Long shopId, Long orderId, List<Map<String, Object>> dataList) {
List<ProductStockSubtractDTO> list = BeanUtil.copyToList(dataList, ProductStockSubtractDTO.class);
if (CollUtil.isEmpty(list)) {
return;
}
boolean isLowWarnLine = false;
for (ProductStockSubtractDTO dto : list) {
Product product = productMapper.selectOneById(dto.getProductId());
productMapper.updateProductStockNum(dto.getProductId(), dto.getShopId(), "add", dto.getNum());
// 记录商品库存流水
ProductStockFlow flow = new ProductStockFlow();
flow.setCreateUserId(1L);
flow.setCreateUserName("银收客");
flow.setShopId(shopId);
flow.setProductId(product.getId());
flow.setProductName(product.getName());
flow.setBeforeNumber(NumberUtil.toBigDecimal(product.getStockNumber()));
flow.setInOutNumber(NumberUtil.toBigDecimal(dto.getNum()));
flow.setAfterNumber(NumberUtil.add(NumberUtil.toBigDecimal(product.getStockNumber()), NumberUtil.toBigDecimal(dto.getNum())));
flow.setInOutType(InOutTypeEnum.OUT.value());
flow.setInOutItem(InOutItemEnum.ORDER_OUT.value());
flow.setRemark("红冲订单取消/退菜/退单消耗的库存");
flow.setOrderId(orderId);
productStockFlowService.saveFlow(flow);
refreshRedisProdStock(shopId, product.getId(), flow.getAfterNumber());
Integer warnLine = ObjUtil.defaultIfNull(product.getWarnLine(), 10);
if (!isLowWarnLine && (NumberUtil.isLessOrEqual(flow.getBeforeNumber(), BigDecimal.ZERO) || NumberUtil.isLess(flow.getAfterNumber(), Convert.toBigDecimal(warnLine)))) {
isLowWarnLine = true;
}
// 查询商品绑定耗材信息
List<ProdConsRelation> relationList = prodConsRelationMapper.selectListByQuery(QueryWrapper.create().eq(ProdConsRelation::getProductId, dto.getProductId()));
if (CollUtil.isEmpty(relationList)) {
continue;
}
for (ProdConsRelation prodConsRelation : relationList) {
// 耗材id
Long consInfoId = prodConsRelation.getConsInfoId();
// 耗材消耗数量
BigDecimal surplusStock = prodConsRelation.getSurplusStock();
if (surplusStock == null) {
continue;
}
// 实际消耗数量 = 耗材消耗数量 * 商品购买数量
surplusStock = NumberUtil.mul(surplusStock, dto.getNum());
ConsInfo consInfo = consInfoMapper.selectOneById(consInfoId);
if (consInfo == null) {
continue;
}
BigDecimal stockNumber = consInfo.getStockNumber();
consInfo.setStockNumber(NumberUtil.add(stockNumber, surplusStock));
// 更新耗材库存数量
consInfoMapper.update(consInfo);
// 插入耗材流水记录
ConsStockFlow consStockFlow = new ConsStockFlow();
consStockFlow.setShopId(shopId);
consStockFlow.setInOutType(InOutTypeEnum.OUT.value());
consStockFlow.setInOutItem(InOutItemEnum.ORDER_OUT.value());
consStockFlow.setInOutDate(LocalDate.now());
consStockFlow.setConId(consInfo.getId());
consStockFlow.setConName(consInfo.getConName());
consStockFlow.setUnitName(consInfo.getConUnit());
consStockFlow.setBeforeNumber(stockNumber);
consStockFlow.setInOutNumber(surplusStock);
consStockFlow.setAfterNumber(consInfo.getStockNumber());
consStockFlow.setSubTotal(NumberUtil.mul(surplusStock, consInfo.getPrice()));
consStockFlow.setProductId(dto.getProductId());
//consStockFlow.setSkuId(0L);
consStockFlow.setRemark("红冲订单取消/退菜/退单消耗的库存");
consStockFlow.setOrderId(orderId);
consStockFlowService.saveFlow(consStockFlow);
}
}
if (isLowWarnLine) {
ThreadUtil.execAsync(() -> rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId)));
}
log.info("ProductService.--------------------------------------------库存更新成功");
public void orderCancelRecoverStock(Long shopId, Long orderId, List<ProductStockVO> list) {
productService.consStockByProduct(shopId, InOutTypeEnum.IN, InOutItemEnum.ORDER_IN, list, orderId, "订单取消/过期返还库存");
}
@Override
@Transactional(rollbackFor = Exception.class)
public void orderRefundReturnStock(Long shopId, Long orderId, List<Map<String, Object>> dataList) {
List<ProductStockSubtractDTO> list = BeanUtil.copyToList(dataList, ProductStockSubtractDTO.class);
if (CollUtil.isEmpty(list)) {
return;
}
boolean isLowWarnLine = false;
for (ProductStockSubtractDTO dto : list) {
Product product = productMapper.selectOneById(dto.getProductId());
// 商品是否允许退款退货时归还库存
if (SystemConstants.OneZero.ONE == product.getIsRefundStock() && SystemConstants.OneZero.ONE == product.getIsStock()) {
productMapper.updateProductStockNum(dto.getProductId(), dto.getShopId(), "add", dto.getNum());
// 记录商品库存流水
ProductStockFlow flow = new ProductStockFlow();
flow.setCreateUserId(1L);
flow.setCreateUserName("银收客");
flow.setShopId(shopId);
flow.setProductId(product.getId());
flow.setProductName(product.getName());
flow.setBeforeNumber(NumberUtil.toBigDecimal(product.getStockNumber()));
flow.setInOutNumber(NumberUtil.toBigDecimal(dto.getNum()));
flow.setAfterNumber(NumberUtil.add(NumberUtil.toBigDecimal(product.getStockNumber()), NumberUtil.toBigDecimal(dto.getNum())));
flow.setInOutType(InOutTypeEnum.OUT.value());
flow.setInOutItem(InOutItemEnum.ORDER_OUT.value());
flow.setRemark("红冲订单取消/退菜/退单消耗的库存");
flow.setOrderId(orderId);
productStockFlowService.saveFlow(flow);
// String key = StrUtil.format(SHOP_PRODUCT_STOCK, shopId, product.getId());
refreshRedisProdStock(shopId, product.getId(), flow.getAfterNumber());
Integer warnLine = ObjUtil.defaultIfNull(product.getWarnLine(), 10);
if (!isLowWarnLine && (NumberUtil.isLessOrEqual(flow.getBeforeNumber(), BigDecimal.ZERO) || NumberUtil.isLess(flow.getAfterNumber(), Convert.toBigDecimal(warnLine)))) {
isLowWarnLine = true;
}
}
// 查询商品绑定耗材信息
List<ProdConsRelation> relationList = prodConsRelationMapper.selectListByQuery(QueryWrapper.create().eq(ProdConsRelation::getProductId, dto.getProductId()));
if (CollUtil.isEmpty(relationList)) {
continue;
}
for (ProdConsRelation prodConsRelation : relationList) {
// 耗材id
Long consInfoId = prodConsRelation.getConsInfoId();
// 耗材消耗数量
BigDecimal surplusStock = prodConsRelation.getSurplusStock();
if (surplusStock == null || surplusStock.compareTo(BigDecimal.ZERO) == 0) {
continue;
}
// 实际消耗数量 = 耗材消耗数量 * 商品购买数量
surplusStock = NumberUtil.mul(surplusStock, dto.getNum());
ConsInfo consInfo = consInfoMapper.selectOneById(consInfoId);
if (consInfo == null || consInfo.getIsStock() == SystemConstants.OneZero.ZERO || consInfo.getIsRefundStock() == SystemConstants.OneZero.ZERO) {
continue;
}
BigDecimal stockNumber = consInfo.getStockNumber();
consInfo.setStockNumber(NumberUtil.add(stockNumber, surplusStock));
// 更新耗材库存数量
consInfoMapper.update(consInfo);
// 插入耗材流水记录
ConsStockFlow consStockFlow = new ConsStockFlow();
consStockFlow.setShopId(shopId);
consStockFlow.setInOutType(InOutTypeEnum.OUT.value());
consStockFlow.setInOutItem(InOutItemEnum.ORDER_OUT.value());
consStockFlow.setInOutDate(LocalDate.now());
consStockFlow.setConId(consInfo.getId());
consStockFlow.setConName(consInfo.getConName());
consStockFlow.setUnitName(consInfo.getConUnit());
consStockFlow.setBeforeNumber(stockNumber);
consStockFlow.setInOutNumber(surplusStock);
consStockFlow.setAfterNumber(consInfo.getStockNumber());
consStockFlow.setSubTotal(NumberUtil.mul(surplusStock, consInfo.getPrice()));
consStockFlow.setProductId(dto.getProductId());
// consStockFlow.setSkuId(0L);
consStockFlow.setOrderId(orderId);
consStockFlow.setRemark("红冲订单取消/退菜/退单消耗的库存");
consStockFlowService.saveFlow(consStockFlow);
}
}
if (isLowWarnLine) {
ThreadUtil.execAsync(() -> rabbitPublisher.sendProductInfoChangeMsg(Convert.toStr(shopId)));
}
log.info("ProductService.--------------------------------------------库存更新成功");
public void orderRefundReturnStock(Long shopId, Long orderId, List<ProductStockVO> list) {
productService.consStockByProduct(shopId, InOutTypeEnum.IN, InOutItemEnum.ORDER_IN, list, orderId, "订单退菜/退款返还库存");
}
@Override
@@ -326,13 +63,4 @@ public class ProductRpcServiceImpl implements ProductRpcService {
String key = ADMIN_CLIENT_PRODUCT_LIST + "::" + shopId + "::" + categoryId;
redisService.del(key);
}
private void refreshRedisProdStock(Long shopId, Long productId, BigDecimal stockNumber) {
String key = StrUtil.format(SHOP_PRODUCT_STOCK, shopId, productId);
if (NumberUtil.isLessOrEqual(stockNumber, BigDecimal.ZERO)) {
redisService.del(key);
} else {
redisService.set(key, stockNumber.intValue());
}
}
}

View File

@@ -2,6 +2,8 @@ package com.czg.service.product.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
@@ -9,6 +11,7 @@ import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONWriter;
import com.czg.config.RabbitPublisher;
import com.czg.constant.CacheConstant;
import com.czg.constants.SystemConstants;
import com.czg.excel.ExcelExportUtil;
@@ -21,6 +24,7 @@ import com.czg.product.param.*;
import com.czg.product.service.*;
import com.czg.product.vo.ProductGroupVo;
import com.czg.product.vo.ProductStatisticsVo;
import com.czg.product.vo.ProductStockVO;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.service.product.mapper.*;
@@ -29,17 +33,14 @@ import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.DbChain;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
@@ -48,7 +49,6 @@ import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.TextStyle;
import java.util.*;
import java.util.stream.Collectors;
import static com.czg.constant.CacheConstant.ADMIN_CLIENT_PRODUCT_LIST;
import static com.czg.product.entity.table.ProductTableDef.PRODUCT;
@@ -68,17 +68,16 @@ import static com.czg.product.entity.table.ShopProdUnitTableDef.SHOP_PROD_UNIT;
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
private final ProdSkuMapper prodSkuMapper;
private final ProdConsRelationMapper prodConsRelationMapper;
private final ProdConsRelationService prodConsRelationService;
private final ConsInfoMapper consInfoMapper;
private final ProductStockFlowMapper productStockFlowMapper;
private final ProductStockFlowService productStockFlowService;
private final ConsStockFlowService consStockFlowService;
private final SensitiveOperationService sensitiveOperationService;
private final ProdGroupRelationMapper prodGroupRelationMapper;
private final ProductStockFlowService productStockFlowService;
private final RedisService redisService;
@Resource
@Lazy
private ShopProdCategoryService shopProdCategoryService;
private RabbitPublisher rabbitPublisher;
private QueryWrapper buildQueryWrapper(ProductDTO param) {
QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
@@ -152,7 +151,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
lowMemberPriceIsPresent.ifPresent(record::setLowMemberPrice);
}
record.setSkuList(skuList);
List<ProdConsRelationDTO> consList = prodConsRelationMapper.selectListByProdId(record.getId());
List<ProdConsRelationDTO> consList = prodConsRelationService.selectListByProdId(record.getId());
record.setConsList(consList);
if (CollUtil.isNotEmpty(consList)) {
List<Long> consIds = consList.stream().map(ProdConsRelationDTO::getConsInfoId).distinct().toList();
@@ -174,9 +173,22 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
@Override
public List<ProductDTO> getProductList(ProductDTO param) {
QueryWrapper queryWrapper = buildFullQueryWrapper(param);
//queryWrapper.eq(Product::getIsSale, SystemConstants.OneZero.ONE);
List<ProductDTO> records = super.listAs(queryWrapper, ProductDTO.class);
buildProductExtInfo(records);
records.forEach(record -> {
record.setProGroupVo(JSONArray.parseArray(record.getGroupSnap().toString(), ProductGroupVo.class));
List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query().eq(ProdSku::getProductId, record.getId()).eq(ProdSku::getIsDel, SystemConstants.OneZero.ZERO), ProdSkuDTO.class);
if (CollUtil.isNotEmpty(skuList)) {
Optional<BigDecimal> lowPriceIsPresent = skuList.stream().map(obj -> NumberUtil.nullToZero(obj.getSalePrice())).min(BigDecimal::compareTo);
lowPriceIsPresent.ifPresent(record::setLowPrice);
Optional<BigDecimal> lowMemberPriceIsPresent = skuList.stream().map(obj -> NumberUtil.nullToZero(obj.getMemberPrice())).min(BigDecimal::compareTo);
lowMemberPriceIsPresent.ifPresent(record::setLowMemberPrice);
}
record.setSkuList(skuList);
record.setConsList(prodConsRelationService.listAs(query()
.eq(ProdConsRelation::getProductId, record.getId())
.eq(ProdConsRelation::getShopId, record.getShopId()), ProdConsRelationDTO.class));
});
return records;
}
@@ -271,7 +283,6 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
.setMemberPrice(getMainSkuMemberPrice(exportDTO))
.setType(exportDTO.getType())
.setGroupType(exportDTO.getGroupType())
.setStockNumber(exportDTO.getStockNumber())
.setIsSale(getMainSkuIsSale(exportDTO))
.setGroupTitleName(proGroupDTO.getTitle())
.setGroupProductNumber(Optional.ofNullable(proGroupDTO.getNumber()).map(String::valueOf).orElse(""))
@@ -329,62 +340,47 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
}
@Override
public List<ProductDTO> getProductCacheList(ProductDTO param) {
Long shopId = param.getShopId();
initProductCache(shopId);
String prefix = ADMIN_CLIENT_PRODUCT_LIST + "::" + shopId + "::";
public List<ProductDTO> getProductCacheList(Long shopId, Long categoryId) {
String key = ADMIN_CLIENT_PRODUCT_LIST + "::" + shopId;
List<ProductDTO> list;
if (param.getCategoryId() == null) {
list = new ArrayList<>();
Set<String> keys = redisService.rightLikeKey(prefix);
for (String key : keys) {
List<ProductDTO> prodList = redisService.getJsonToBeanList(key, ProductDTO.class);
if(CollUtil.isNotEmpty(prodList)) {
list.addAll(prodList);
}
if (categoryId == null) {
if (!redisService.hasKey(key)) {
ProductDTO param = new ProductDTO();
param.setShopId(shopId);
list = getProductList(param);
redisService.setJsonStr(key, list);
} else {
list = redisService.getJsonToBeanList(key, ProductDTO.class);
}
} else {
String key = prefix + param.getCategoryId();
list = redisService.getJsonToBeanList(key, ProductDTO.class);
key = key + "::" + categoryId;
if (!redisService.hasKey(key)) {
list = initProductCacheByCategoryId(shopId, categoryId);
} else {
list = redisService.getJsonToBeanList(key, ProductDTO.class);
}
// 重新进行排序
list = list.stream()
.sorted(Comparator.comparingInt(ProductDTO::getIsSoldStock))
.sorted(Comparator.comparingInt(ProductDTO::getIsSale).reversed())
.sorted(Comparator.comparingInt(ProductDTO::getSort).reversed())
.sorted(Comparator.comparingLong(ProductDTO::getId).reversed())
.toList();
}
if (StrUtil.isNotEmpty(param.getName())) {
list = list.stream().filter(obj -> StrUtil.contains(obj.getName(), param.getName())).toList();
}
// 重新进行排序
list = list.stream()
.sorted(Comparator.comparingInt(ProductDTO::getIsSoldStock))
.sorted(Comparator.comparingInt(ProductDTO::getIsSale).reversed())
.sorted(Comparator.comparingInt(ProductDTO::getSort).reversed())
.sorted(Comparator.comparingLong(ProductDTO::getId).reversed())
.toList();
return list;
}
/**
* 初始化商品缓存数据
*/
private void initProductCache(Long shopId) {
private List<ProductDTO> initProductCacheByCategoryId(Long shopId, Long categoryId) {
ProductDTO param = new ProductDTO();
param.setShopId(shopId);
param.setCategoryId(categoryId);
List<ProductDTO> productList = getProductList(param);
Map<Long, List<ProductDTO>> categoryMap = productList.stream().filter(item -> item.getCategoryId() != null).collect(Collectors.groupingBy(ProductDTO::getCategoryId));
ShopProdCategoryDTO dto = new ShopProdCategoryDTO();
dto.setShopId(shopId);
List<ShopProdCategoryDTO> categoryList = shopProdCategoryService.getShopProdCategoryList(dto);
String prefix = ADMIN_CLIENT_PRODUCT_LIST + "::" + shopId + "::";
for (ShopProdCategoryDTO category : categoryList) {
String key = prefix + category.getId();
boolean b = redisService.hasKey(key);
if (!b) {
List<ProductDTO> list = categoryMap.get(category.getId());
if (CollUtil.isNotEmpty(list)) {
redisService.setJsonStr(key, list);
} else {
List<ProductDTO> empty = new ArrayList<>();
redisService.setJsonStr(key, empty);
}
}
}
String key = ADMIN_CLIENT_PRODUCT_LIST + "::" + shopId + "::" + categoryId;
redisService.setJsonStr(key, productList);
return productList;
}
/**
@@ -397,23 +393,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
for (Long categoryId : categoryIds) {
redisService.del(prefix + categoryId);
}
}
/**
* 系统启动会一次性加载商品缓存数据,防止首次访问时加载缓慢的问题
*/
@PostConstruct
public void initProductListCache() {
log.info("系统启动后初始化商品列表缓存,开始...");
List<Long> shopIdList = DbChain.table("tb_shop_info").select("id").listAs(Long.class);
for (Long shopId : shopIdList) {
log.info("商品列表缓存>>当前店铺:{}", shopId);
ProductDTO dto = new ProductDTO();
dto.setShopId(shopId);
getProductCacheList(dto);
log.info("商品列表缓存>>当前店铺:{},初始化结束", shopId);
}
log.info("系统启动后初始化商品列表缓存,结束。");
redisService.del(ADMIN_CLIENT_PRODUCT_LIST + "::" + shopId);
}
/**
@@ -461,7 +441,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
}
List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query().eq(ProdSku::getProductId, id).eq(ProdSku::getIsDel, SystemConstants.OneZero.ZERO), ProdSkuDTO.class);
dto.setSkuList(skuList);
List<ProdConsRelationDTO> consList = prodConsRelationMapper.selectListByProdId(dto.getId());
List<ProdConsRelationDTO> consList = prodConsRelationService.selectListByProdId(dto.getId());
dto.setConsList(consList);
dto.setRelatedRecommendJson(getRelateProductList(dto.getRelatedRecommend()));
return dto;
@@ -493,8 +473,6 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
entity.setRelatedRecommend(dto.getRelatedRecommendStr());
super.save(entity);
dto.setId(entity.getId());
// 清除商品分类列表缓存
clearProductCache(entity.getCategoryId());
List<ProdSkuDTO> skuList = dto.getSkuList();
if (CollUtil.isNotEmpty(skuList)) {
List<ProdSku> prodSkuList = new ArrayList<>();
@@ -510,24 +488,12 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
}
prodSkuMapper.insertBatch(prodSkuList);
}
if (entity.getIsStock() == SystemConstants.OneZero.ZERO) {
return;
}
// 记录商品库存流水
ProductStockFlow flow = new ProductStockFlow();
Long createUserId = StpKit.USER.getLoginIdAsLong();
String createUserName = StpKit.USER.getAccount();
flow.setCreateUserId(createUserId);
flow.setCreateUserName(createUserName);
flow.setShopId(shopId);
flow.setProductId(entity.getId());
flow.setProductName(entity.getName());
flow.setBeforeNumber(BigDecimal.ZERO);
flow.setInOutNumber(NumberUtil.toBigDecimal(entity.getStockNumber()));
flow.setAfterNumber(NumberUtil.toBigDecimal(entity.getStockNumber()));
flow.setInOutType(InOutTypeEnum.IN.value());
flow.setInOutItem(InOutItemEnum.WIN_IN.value());
productStockFlowService.saveFlow(flow);
ProdConsBindDTO prodConsBindDTO = new ProdConsBindDTO();
prodConsBindDTO.setId(entity.getId());
prodConsBindDTO.setConsList(dto.getConsList());
prodConsRelationService.saveProdConsRelation(prodConsBindDTO);
// 清除商品分类列表缓存
clearProductCache(entity.getCategoryId());
}
@Override
@@ -561,19 +527,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
}
entity.setRelatedRecommend(dto.getRelatedRecommendStr());
super.updateById(entity);
// 清除商品分类列表缓存
clearProductCache(old.getCategoryId());
if (!old.getCategoryId().equals(dto.getCategoryId())) {
clearProductCache(entity.getCategoryId());
}
if (ObjUtil.defaultIfNull(dto.getIsStock(), old.getIsStock()) == SystemConstants.OneZero.ZERO) {
redisService.del(StrUtil.format(CacheConstant.SHOP_PRODUCT_STOCK, shopId, dto.getId()));
Boolean b = redisService.hasKey(StrUtil.format(CacheConstant.SHOP_PRODUCT_STOCK, shopId, dto.getId()));
log.info("删除商品库存缓存:{}-{}", dto.getId(), b);
} else {
redisService.set(StrUtil.format(CacheConstant.SHOP_PRODUCT_STOCK, shopId, dto.getId()), dto.getStockNumber());
log.info("设置商品库存缓存:{}-{}", dto.getId(), dto.getStockNumber());
}
List<ProdSkuDTO> skuList = dto.getSkuList();
// 商品SKU-ID列表
List<Long> skuIdList = prodSkuMapper.selectListByQueryAs(query().select(ProdSku::getId).eq(ProdSku::getProductId, dto.getId()), Long.class);
@@ -597,6 +551,10 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
List<Long> list = skuList.stream().map(ProdSkuDTO::getId).filter(Objects::nonNull).distinct().toList();
skuIdList.removeAll(list);
}
ProdConsBindDTO prodConsBindDTO = new ProdConsBindDTO();
prodConsBindDTO.setId(dto.getId());
prodConsBindDTO.setConsList(dto.getConsList());
prodConsRelationService.saveProdConsRelation(prodConsBindDTO);
if (CollUtil.isNotEmpty(skuIdList)) {
// 逻辑删除无用的SKU数据
UpdateChain.of(ProdSku.class)
@@ -605,85 +563,12 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
.eq(ProdSku::getShopId, shopId)
.update();
}
if (entity.getIsStock() == SystemConstants.OneZero.ZERO) {
return;
// 清除商品分类列表缓存
if (!old.getCategoryId().equals(dto.getCategoryId())) {
clearProductCache(old.getCategoryId(), entity.getCategoryId());
} else {
clearProductCache(old.getCategoryId());
}
// 记录商品库存流水
ProductStockFlow flow = new ProductStockFlow();
Long createUserId = StpKit.USER.getLoginIdAsLong();
String createUserName = StpKit.USER.getAccount();
flow.setCreateUserId(createUserId);
flow.setCreateUserName(createUserName);
flow.setShopId(shopId);
flow.setProductId(old.getId());
flow.setProductName(old.getName());
flow.setBeforeNumber(NumberUtil.toBigDecimal(old.getStockNumber()));
BigDecimal inOutNumber = NumberUtil.sub(NumberUtil.toBigDecimal(entity.getStockNumber()), flow.getBeforeNumber());
// 盘亏
if (NumberUtil.isLess(inOutNumber, BigDecimal.ZERO)) {
flow.setInOutNumber(inOutNumber);
flow.setInOutType(InOutTypeEnum.OUT.value());
flow.setInOutItem(InOutItemEnum.LOSS_OUT.value());
}
// 盘盈
if (NumberUtil.isGreater(inOutNumber, BigDecimal.ZERO)) {
flow.setInOutNumber(inOutNumber);
flow.setInOutType(InOutTypeEnum.IN.value());
flow.setInOutItem(InOutItemEnum.WIN_IN.value());
}
// 盘平
if (NumberUtil.equals(inOutNumber, BigDecimal.ZERO)) {
return;
}
flow.setAfterNumber(NumberUtil.toBigDecimal(entity.getStockNumber()));
productStockFlowService.saveFlow(flow);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateProductStock(ProductModifyStockParam param) {
Product entity = super.getById(param.getId());
if (entity.getIsStock() == SystemConstants.OneZero.ZERO) {
throw new CzgException("该商品未开启库存管理,暂不支持修改库存");
}
if (!entity.getShopId().equals(param.getShopId())) {
return;
}
UpdateChain.of(Product.class)
.set(Product::getStockNumber, param.getStockNumber())
.set(Product::getShopId, param.getShopId())
.eq(Product::getId, param.getId())
.update();
// 记录商品库存流水
ProductStockFlow flow = new ProductStockFlow();
Long createUserId = StpKit.USER.getLoginIdAsLong();
String createUserName = StpKit.USER.getAccount();
flow.setCreateUserId(createUserId);
flow.setCreateUserName(createUserName);
flow.setShopId(param.getShopId());
flow.setProductId(entity.getId());
flow.setProductName(entity.getName());
flow.setBeforeNumber(NumberUtil.toBigDecimal(entity.getStockNumber()));
BigDecimal inOutNumber = NumberUtil.sub(NumberUtil.toBigDecimal(param.getStockNumber()), flow.getBeforeNumber());
// 盘亏
if (NumberUtil.isLess(inOutNumber, BigDecimal.ZERO)) {
flow.setInOutNumber(inOutNumber);
flow.setInOutType(InOutTypeEnum.OUT.value());
flow.setInOutItem(InOutItemEnum.LOSS_OUT.value());
}
// 盘盈
if (NumberUtil.isGreater(inOutNumber, BigDecimal.ZERO)) {
flow.setInOutNumber(inOutNumber);
flow.setInOutType(InOutTypeEnum.IN.value());
flow.setInOutItem(InOutItemEnum.WIN_IN.value());
}
// 盘平
if (NumberUtil.equals(inOutNumber, BigDecimal.ZERO)) {
return;
}
flow.setAfterNumber(NumberUtil.toBigDecimal(entity.getStockNumber()));
flow.setRemark(param.getRemark());
productStockFlowService.saveFlow(flow);
}
@Override
@@ -697,7 +582,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
.eq(Product::getShopId, shopId)
.update();
prodGroupRelationMapper.deleteByQuery(query().eq(ProdGroupRelation::getProductId, id));
prodConsRelationMapper.deleteByQuery(query().eq(ProdConsRelation::getProductId, id));
prodConsRelationService.remove(query().eq(ProdConsRelation::getProductId, id));
// 清除商品分类列表缓存
clearProductCache(categoryId);
}
@@ -737,7 +622,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
.eq(Product::getId, prodSku.getProductId())
.eq(Product::getShopId, shopId)
.update();
}else if(normalCount > 0 && product.getIsSale() == SystemConstants.OneZero.ZERO) {
} else if (normalCount > 0 && product.getIsSale() == SystemConstants.OneZero.ZERO) {
UpdateChain.of(Product.class)
.set(Product::getIsSale, SystemConstants.OneZero.ONE)
.eq(Product::getId, prodSku.getProductId())
@@ -746,7 +631,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
}
sensitiveOperation = sensitiveOperation + "商品:" + product.getName() + " 规格:" + prodSku.getSpecInfo();
} else if (ProductIsSaleTypeEnum.PRODUCT.value().equals(type)) {
if("sale".equals(param.getOptType())){
if ("sale".equals(param.getOptType())) {
UpdateChain.of(Product.class)
.set(Product::getIsSale, isSale)
.eq(Product::getId, id)
@@ -757,12 +642,6 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
.eq(ProdSku::getProductId, id)
.eq(ProdSku::getShopId, shopId)
.update();
}else if("stock".equals(param.getOptType())){
UpdateChain.of(Product.class)
.set(Product::getIsStock, isSale)
.eq(Product::getId, id)
.eq(Product::getShopId, shopId)
.update();
}
Product product = mapper.selectOneById(id);
prodId = product.getId();
@@ -821,6 +700,18 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
Product old = getById(prodId);
Long categoryId = old.getCategoryId();
clearProductCache(categoryId);
ThreadUtil.execAsync(() -> rabbitPublisher.sendConsInfoChangeMsg(Convert.toStr(shopId)));
}
@Override
public void markProductIsAutoSoldOut(Long shopId, ProductIsAutoSaleParam param) {
Product entity = super.getOne(query().eq(Product::getId, param.getId()).eq(Product::getShopId, shopId));
if (entity == null) {
throw new CzgException("商品不存在");
}
Product update = new Product();
update.setIsAutoSoldStock(param.getIsAutoSoldStock());
update(update, query().eq(Product::getId, param.getId()).eq(Product::getShopId, shopId));
}
@Override
@@ -834,14 +725,6 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
super.updateById(entity);
}
@Override
public void stockWarning(Integer warnLine) {
Long shopId = StpKit.USER.getShopId();
UpdateChain.of(Product.class)
.set(Product::getWarnLine, warnLine)
.eq(Product::getShopId, shopId)
.update();
}
@Override
@Transactional(rollbackFor = Exception.class)
@@ -853,16 +736,6 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
if (product == null) {
throw new CzgException("商品不存在");
}
if (product.getIsStock() == SystemConstants.OneZero.ZERO) {
throw new CzgException("商品未开启库存不支持报损操作");
}
// 商品现有库存数量
Integer stockNumber = product.getStockNumber();
product.setStockNumber(stockNumber - param.getNumber());
if (product.getStockNumber() < 0) {
throw new CzgException("商品库存不足,无法报损");
}
super.updateById(product);
// 记录商品库存流水
ProductStockFlow flow = new ProductStockFlow();
flow.setCreateUserId(createUserId);
@@ -870,46 +743,17 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
flow.setShopId(shopId);
flow.setProductId(product.getId());
flow.setProductName(product.getName());
flow.setBeforeNumber(NumberUtil.toBigDecimal(stockNumber));
// flow.setBeforeNumber(NumberUtil.toBigDecimal(stockNumber));
flow.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, NumberUtil.toBigDecimal(param.getNumber())));
flow.setAfterNumber(NumberUtil.toBigDecimal(product.getStockNumber()));
// flow.setAfterNumber(NumberUtil.toBigDecimal(product.getStockNumber()));
flow.setInOutType(InOutTypeEnum.OUT.value());
flow.setInOutItem(InOutItemEnum.DAMAGE_OUT.value());
flow.setImgUrls(JSON.toJSONString(param.getImgUrls()));
productStockFlowService.saveFlow(flow);
// 如果绑定了耗材,则同步更新耗材库存
List<ProdConsRelationDTO> consList = prodConsRelationMapper.selectListByProdId(param.getProductId());
if (CollUtil.isEmpty(consList)) {
return;
}
for (ProdConsRelationDTO consInfo : consList) {
ConsStockFlow entity = new ConsStockFlow();
entity.setCreateUserId(createUserId);
entity.setCreateUserName(createUserName);
entity.setShopId(shopId);
entity.setConId(consInfo.getConsInfoId());
entity.setConName(consInfo.getConName());
entity.setPurchasePrice(consInfo.getPrice());
BigDecimal inOutNumber = NumberUtil.mul(param.getNumber(), consInfo.getSurplusStock());
BigDecimal balance = NumberUtil.sub(consInfo.getStockNumber(), inOutNumber);
if (NumberUtil.isLess(balance, BigDecimal.ZERO)) {
throw new CzgException(StrUtil.format("耗材{}存在发生变动,请刷新后重试", entity.getConName()));
}
entity.setBeforeNumber(consInfo.getStockNumber());
entity.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, inOutNumber));
entity.setAfterNumber(balance);
entity.setInOutType(InOutTypeEnum.OUT.value());
entity.setInOutItem(InOutItemEnum.DAMAGE_OUT.value());
entity.setSubTotal(NumberUtil.mul(inOutNumber, consInfo.getPrice()));
entity.setImgUrls(JSON.toJSONString(param.getImgUrls()));
entity.setRemark("【商品报损,自动报损相关耗材】" + StrUtil.nullToDefault(param.getRemark(), ""));
consStockFlowService.saveFlow(entity);
consInfo.setStockNumber(entity.getAfterNumber());
UpdateChain.of(ConsInfo.class)
.set(ConsInfo::getStockNumber, consInfo.getStockNumber())
.eq(ConsInfo::getId, consInfo.getConsInfoId())
.update();
}
flow.setRemark(param.getRemark());
productStockFlowService.save(flow);
List<ProductStockVO> productStockList = new ArrayList<>();
productStockList.add(new ProductStockVO(param.getProductId(), BigDecimal.valueOf(param.getNumber())));
consStockByProduct(shopId, InOutTypeEnum.OUT, InOutItemEnum.DAMAGE_OUT, productStockList, null, "【商品报损,自动报损相关耗材】");
}
@Override
@@ -925,6 +769,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
public Page<ProductStockFlow> findProductStockFlowPage(ProductStockFlowParam param) {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
param.setProductId(param.getProductId());
PageHelper.startPage(PageUtil.buildPageHelp());
if (InOutItemEnum.ORDER_IN.value().equals(param.getInOutItem())) {
param.setInOutType(InOutTypeEnum.OUT.value());
@@ -935,28 +780,57 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
}
@Override
public void refreshProductStock(ProductDTO param, List<ProductDTO> records) {
QueryWrapper queryWrapper = buildQueryWrapper(param);
queryWrapper.select(PRODUCT.ID, PRODUCT.STOCK_NUMBER);
List<Product> list = super.list(queryWrapper);
if (CollUtil.isEmpty(list)) {
return;
}
Map<Long, Integer> stock = list.stream().collect(Collectors.toMap(Product::getId, Product::getStockNumber));
records.parallelStream().forEach(record -> {
record.setStockNumber(stock.getOrDefault(record.getId(), 0));
if (record.getIsStock() == SystemConstants.OneZero.ONE) {
refreshRedisStock(record.getShopId(), record.getId(), record.getStockNumber());
} else {
redisService.del(StrUtil.format(CacheConstant.SHOP_PRODUCT_STOCK, record.getShopId(), record.getId()));
public void consStockByProduct(Long shopId, InOutTypeEnum type, InOutItemEnum item, List<ProductStockVO> products, Long orderId, String remark) {
if (CollUtil.isEmpty(products)) return;
boolean isSendUp = false;
for (ProductStockVO product : products) {
List<ProdConsRelationDTO> consList = prodConsRelationService.selectStockByProdId(product.getProductId());
if (CollUtil.isEmpty(consList)) return;
for (ProdConsRelationDTO consInfo : consList) {
BigDecimal surplusStock = consInfo.getSurplusStock();
if (surplusStock == null || surplusStock.compareTo(BigDecimal.ZERO) <= 0) {
continue;
}
surplusStock = NumberUtil.mul(surplusStock, product.getNumber());
BigDecimal beforeNumber = consInfo.getStockNumber();
if (InOutTypeEnum.IN.equals(type)) {
consInfo.setStockNumber(NumberUtil.add(beforeNumber, surplusStock));
} else {
consInfo.setStockNumber(NumberUtil.sub(beforeNumber, surplusStock));
}
// 更新耗材库存数量
ConsInfo consInfoUp = new ConsInfo();
consInfoUp.setStockNumber(consInfo.getStockNumber());
consInfoMapper.updateByQuery(consInfoUp, query().eq(ConsInfo::getId, consInfo.getConsInfoId()).eq(ConsInfo::getShopId, consInfo.getShopId()));
ConsStockFlow flow = new ConsStockFlow();
flow.setInOutType(type.value());
flow.setInOutItem(item.value());
flow.setShopId(consInfo.getShopId());
flow.setInOutDate(LocalDate.now());
flow.setConId(consInfo.getConsInfoId());
flow.setConName(consInfo.getConName());
flow.setUnitName(consInfo.getConUnit());
flow.setBeforeNumber(beforeNumber);
flow.setInOutNumber(surplusStock);
flow.setAfterNumber(consInfo.getStockNumber());
flow.setPurchasePrice(consInfo.getPrice());
flow.setSubTotal(BigDecimal.ZERO);
if (flow.getPurchasePrice() != null && flow.getPurchasePrice().compareTo(BigDecimal.ZERO) > 0) {
flow.setSubTotal(NumberUtil.mul(surplusStock, flow.getPurchasePrice()));
}
flow.setProductId(product.getProductId());
flow.setOrderId(orderId);
flow.setRemark(remark);
consStockFlowService.save(flow);
boolean b = consStockFlowService.sendStockMsg(flow, consInfo.getConWarning());
if (b) isSendUp = b;
}
});
}
if (isSendUp) {
ThreadUtil.execAsync(() -> rabbitPublisher.sendConsInfoChangeMsg(Convert.toStr(shopId)));
}
}
private void refreshRedisStock(Long shopId, Long productId, Integer stockNumber) {
String key = StrUtil.format(CacheConstant.SHOP_PRODUCT_STOCK, shopId, productId);
redisService.set(key, stockNumber);
}
private List<RelatedProductDTO> getRelateProductList(String relatedProduct) {
if (StrUtil.isNotBlank(relatedProduct) && !"[]".equals(relatedProduct)) {

View File

@@ -1,25 +1,12 @@
package com.czg.service.product.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.product.entity.Product;
import com.czg.product.entity.ProductStockFlow;
import com.czg.product.service.ProductStockFlowService;
import com.czg.service.product.mapper.ConsInfoMapper;
import com.czg.service.product.mapper.ProductMapper;
import com.czg.service.product.mapper.ProductStockFlowMapper;
import com.czg.service.product.util.WxAccountUtil;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
/**
* 商品库存流水服务实现类
*
@@ -30,31 +17,4 @@ import java.util.List;
@Slf4j
public class ProductStockFlowServiceImpl extends ServiceImpl<ProductStockFlowMapper, ProductStockFlow> implements ProductStockFlowService {
@Resource
private ProductMapper productMapper;
@Resource
private ConsInfoMapper consInfoMapper;
@Resource
private WxAccountUtil wxAccountUtil;
@Override
public void saveFlow(ProductStockFlow entity) {
mapper.insert(entity);
Long shopId = entity.getShopId();
BigDecimal afterNumber = entity.getAfterNumber();
Product product = productMapper.selectOneById(entity.getProductId());
String shopName = productMapper.getShopName(shopId);
BigDecimal warnLine = Convert.toBigDecimal(product.getWarnLine());
// 库存小于警告值,发送消息提醒
if (NumberUtil.isLess(afterNumber, warnLine)) {
List<String> openIdList = consInfoMapper.findOpenIdList(shopId, "pro");
if (CollUtil.isEmpty(openIdList)) {
return;
}
String productName = StrUtil.sub(product.getName(), 0, 10).concat("...");
String conName = StrUtil.format("{}数量<预警值{}", productName, warnLine);
ThreadUtil.execAsync(() -> openIdList.parallelStream().forEach(openId ->
wxAccountUtil.sendStockMsg("商品库存预警", shopName, conName, afterNumber, openId)));
}
}
}

View File

@@ -15,12 +15,11 @@ import com.czg.service.product.mapper.ShopProdCategoryMapper;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.List;
@@ -30,7 +29,7 @@ import java.util.List;
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-02-10
*/
@Service
@DubboService
public class ShopProdCategoryServiceImpl extends ServiceImpl<ShopProdCategoryMapper, ShopProdCategory> implements ShopProdCategoryService {
@Resource
@@ -121,22 +120,18 @@ public class ShopProdCategoryServiceImpl extends ServiceImpl<ShopProdCategoryMap
@Override
public void disableShopProdCategory(Long id) {
Long shopId = StpKit.USER.getShopId(0L);
UpdateChain.of(ShopProdCategory.class)
.set(ShopProdCategory::getStatus, SystemConstants.OneZero.ZERO)
.eq(ShopProdCategory::getId, id)
.eq(ShopProdCategory::getShopId, shopId)
.update();
ShopProdCategory prodCategory = new ShopProdCategory();
prodCategory.setStatus(SystemConstants.OneZero.ZERO);
update(prodCategory, query().eq(ShopProdCategory::getId, id).eq(ShopProdCategory::getShopId, shopId));
productService.clearProductCache(id);
}
@Override
public void enableShopProdCategory(Long id) {
Long shopId = StpKit.USER.getShopId(0L);
UpdateChain.of(ShopProdCategory.class)
.set(ShopProdCategory::getStatus,SystemConstants.OneZero.ONE)
.eq(ShopProdCategory::getId, id)
.eq(ShopProdCategory::getShopId, shopId)
.update();
ShopProdCategory prodCategory = new ShopProdCategory();
prodCategory.setStatus(SystemConstants.OneZero.ONE);
update(prodCategory, query().eq(ShopProdCategory::getId, id).eq(ShopProdCategory::getShopId, shopId));
productService.clearProductCache(id);
}

View File

@@ -108,7 +108,8 @@ public class ShopSyncServiceImpl implements ShopSyncService {
ShopInfo sourceShop = shopInfoService.getById(sourceShopId);
if (StrUtil.isBlank(sourceShop.getShopType()) || "only".equals(sourceShop.getShopType())
|| sourceShop.getIsHeadShop() == null || sourceShop.getIsHeadShop() != 1) {
throw new CzgException("同步失败,源店铺不是主店铺或源店铺是单店");
log.error("同步失败,源店铺不是主店铺或源店铺是单店");
return null;
}
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.select(column(ShopConfig::getId));
@@ -238,7 +239,7 @@ public class ShopSyncServiceImpl implements ShopSyncService {
unitMap.put(unit.getSyncId(), unit.getId());
}
}
;
buildNotice(mainMapList, "单位同步", pointShopUnits.size(), null, null);
buildNotice(mainMapList, "单位新增", unitMap.size() - pointShopUnits.size(), null, null);
log.info("单位同步,源{}个,已有{}个,同步{}个", list.size(), pointShopUnits.size(), unitMap.size() - pointShopUnits.size());
@@ -546,7 +547,6 @@ public class ShopSyncServiceImpl implements ShopSyncService {
tbProductNew.setCategoryId(tbProduct.getCategoryId() != null ? cateGoryMap.get(tbProduct.getCategoryId()) : null);
tbProductNew.setSpecId(tbProduct.getSpecId() != null ? specMap.get(tbProduct.getSpecId()) : null);
tbProductNew.setUnitId(tbProduct.getUnitId() != null ? unitMap.get(tbProduct.getUnitId()) : null);
tbProductNew.setStockNumber(0);
if (CollUtil.isNotEmpty(pointProducts)) {
tbProductNew.setIsSale(0);
}
@@ -565,9 +565,10 @@ public class ShopSyncServiceImpl implements ShopSyncService {
tbProductNew.setType(tbProduct.getType());
tbProductNew.setGroupType(tbProduct.getGroupType());
tbProductNew.setPackFee(tbProduct.getPackFee());
tbProductNew.setIsAutoSoldStock(tbProduct.getIsAutoSoldStock());
tbProductNew.setRefundMode(tbProduct.getRefundMode());
tbProductNew.setCoverImg(tbProduct.getCoverImg());
tbProductNew.setImages(tbProduct.getImages());
tbProductNew.setWarnLine(tbProduct.getWarnLine());
tbProductNew.setWeight(tbProduct.getWeight());
tbProductNew.setSelectSpecInfo(tbProduct.getSelectSpecInfo());
tbProductNew.setSort(tbProduct.getSort());
@@ -655,16 +656,13 @@ public class ShopSyncServiceImpl implements ShopSyncService {
newEntity.setEndTime(null);
newEntity.setDays(null);
newEntity.setIsHot(null);
newEntity.setIsStock(null);
newEntity.setIsSoldStock(null);
newEntity.setStockNumber(null);
newEntity.setIsSale(null);
newEntity.setIsRefundStock(null);
productService.updateById(newEntity);
} else {
newEntity.setId(null);
newEntity.setIsSale(0);
newEntity.setStockNumber(0);
productService.save(newEntity);
}
if (newEntity.getCategoryId() != null) {

View File

@@ -2,7 +2,6 @@ package com.czg.service.product.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
@@ -12,18 +11,15 @@ import com.czg.constants.SystemConstants;
import com.czg.exception.CzgException;
import com.czg.product.dto.ProdGroupRelationDTO;
import com.czg.product.dto.ProdSkuDTO;
import com.czg.product.entity.ProdGroup;
import com.czg.product.entity.ProdGroupRelation;
import com.czg.product.entity.ProdSku;
import com.czg.product.entity.Product;
import com.czg.product.entity.*;
import com.czg.product.param.ShopProductSkuParam;
import com.czg.product.service.ProdConsRelationService;
import com.czg.product.service.UProductService;
import com.czg.product.vo.ShopGroupProductVo;
import com.czg.product.vo.ShopProductInfoVo;
import com.czg.product.vo.ShopProductSkuInfoVo;
import com.czg.product.vo.ShopProductVo;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.service.product.mapper.ProdGroupMapper;
import com.czg.service.product.mapper.ProdGroupRelationMapper;
import com.czg.service.product.mapper.ProdSkuMapper;
@@ -56,7 +52,8 @@ public class UProductServiceImpl extends ServiceImpl<ProductMapper, Product> imp
private final ProdSkuMapper prodSkuMapper;
private final ProdGroupMapper prodGroupMapper;
private final ProdGroupRelationMapper prodGroupRelationMapper;
private final RedisService redisService;
private final ProdConsRelationService prodConsRelationService;
@Override
@Cacheable(value = CacheConstant.USER_CLIENT_HOTS_PRODUCT, key = "#shopId", unless = "#result.isEmpty()")
@@ -68,6 +65,9 @@ public class UProductServiceImpl extends ServiceImpl<ProductMapper, Product> imp
.eq(ProdSku::getIsGrounding, SystemConstants.OneZero.ONE)
.eq(ProdSku::getIsDel, SystemConstants.OneZero.ZERO), ProdSkuDTO.class);
item.setSkuList(skuList);
item.setConsList(prodConsRelationService.list(query()
.eq(ProdConsRelation::getProductId, item.getId())
.eq(ProdConsRelation::getShopId, item.getShopId())));
});
return list;
}
@@ -86,6 +86,9 @@ public class UProductServiceImpl extends ServiceImpl<ProductMapper, Product> imp
.eq(ProdSku::getIsGrounding, SystemConstants.OneZero.ONE)
.eq(ProdSku::getIsDel, SystemConstants.OneZero.ZERO), ProdSkuDTO.class);
item.setSkuList(skuList);
item.setConsList(prodConsRelationService.list(query()
.eq(ProdConsRelation::getProductId, item.getId())
.eq(ProdConsRelation::getShopId, item.getShopId())));
});
Map<Long, ShopProductVo> productKv = productAllList.stream().collect(Collectors.toMap(ShopProductVo::getId, shopProductVo -> shopProductVo));
List<Long> prodGroupIdList = groupList.stream().map(ShopGroupProductVo::getId).distinct().toList();
@@ -166,55 +169,11 @@ public class UProductServiceImpl extends ServiceImpl<ProductMapper, Product> imp
, ShopProductSkuInfoVo.class);
// throw new CzgException("商品SKU不可售或不存在");
if (data != null) {
data.setStockNumber(ObjUtil.defaultIfNull(product.getStockNumber(), 0));
data.setIsSoldStock(data.getIsPauseSale());
data.setIsSale(data.getIsGrounding());
data.setIsStock(product.getIsStock());
return data;
}
return null;
}
@Override
public Map<Long, Integer> findShopProductStock(Long shopId) {
List<Product> list = productMapper.selectListByQuery(query().select(Product::getId, Product::getStockNumber).eq(Product::getShopId, shopId));
if (CollUtil.isEmpty(list)) {
return null;
}
return list.stream().collect(Collectors.toMap(Product::getId, Product::getStockNumber));
}
@Override
public void refreshProductStock(Long shopId, List<ShopProductVo> productList) {
Map<Long, Integer> stock = findShopProductStock(shopId);
if (MapUtil.isEmpty(stock)) {
return;
}
productList.parallelStream().forEach(record -> {
record.setStockNumber(stock.getOrDefault(record.getId(), 0));
refreshRedisStock(record.getShopId(), record.getId(), record.getStockNumber());
});
}
@Override
public void refreshProductStock(Map<Long, Integer> productStock, List<ShopProductVo> productList) {
if (MapUtil.isEmpty(productStock)) {
return;
}
productList.parallelStream().forEach(record -> {
record.setStockNumber(productStock.getOrDefault(record.getId(), 0));
if (record.getIsStock() == SystemConstants.OneZero.ONE) {
refreshRedisStock(record.getShopId(), record.getId(), record.getStockNumber());
} else {
redisService.del(StrUtil.format(CacheConstant.SHOP_PRODUCT_STOCK, record.getShopId(), record.getId()));
}
});
}
private void refreshRedisStock(Long shopId, Long productId, Integer stockNumber) {
String key = StrUtil.format(CacheConstant.SHOP_PRODUCT_STOCK, shopId, productId);
redisService.set(key, stockNumber);
}
/**
* 计算是否在可售时间内
@@ -290,24 +249,4 @@ public class UProductServiceImpl extends ServiceImpl<ProductMapper, Product> imp
DayOfWeek dayOfWeek = currentDate.getDayOfWeek();
return dayOfWeek.getDisplayName(TextStyle.FULL, Locale.ENGLISH);
}
public static void main(String[] args) {
LocalTime startTime = LocalTime.of(17, 0, 0);
LocalTime endTime = LocalTime.of(23, 0, 0);
LocalTime now = LocalTime.now().withNano(0);
if (startTime.isBefore(endTime)) {
if (now.isAfter(startTime) && now.isBefore(endTime)) {
System.out.println("");
} else {
System.out.println("不在");
}
} else {
if (now.isAfter(startTime) || now.isBefore(endTime)) {
System.out.println("");
} else {
System.out.println("不在");
}
}
}
}

View File

@@ -20,7 +20,20 @@
t2.stock_number,
t1.surplus_stock
FROM tb_prod_cons_relation t1
LEFT JOIN tb_cons_info t2 on t1.cons_info_id = t2.id
inner JOIN tb_cons_info t2 on t1.cons_info_id = t2.id
WHERE t1.product_id = #{prodId}
</select>
<select id="selectStockByProdId" resultType="com.czg.product.dto.ProdConsRelationDTO">
SELECT t1.*,
t2.con_unit,
t2.con_name,
t2.price,
t2.stock_number,
t2.con_warning,
t1.surplus_stock
FROM tb_prod_cons_relation t1
inner JOIN tb_cons_info t2 on t1.cons_info_id = t2.id and t2.is_stock = 1
WHERE t1.product_id = #{prodId}
</select>
</mapper>

View File

@@ -17,7 +17,6 @@
t1.unit_id,
t1.weight,
t1.end_time,
t1.is_stock,
t1.pack_fee,
t1.cover_img,
t1.warn_line,
@@ -29,7 +28,6 @@
t1.short_title,
t1.update_time,
t1.is_sold_stock,
t1.stock_number,
t1.is_refund_stock,
t1.select_spec_info,
t1.group_category_id,
@@ -82,7 +80,6 @@
t3.name as unit_name,
t1.is_sold_stock,
t1.sync_id as syncId,
t1.stock_number,
t1.type,
t1.group_type,
t1.days,
@@ -95,7 +92,7 @@
t1.pack_fee,
ifnull(t4.sales_volume, 0) as sales_volume,
t1.shop_id,
t1.is_stock,
t1.is_auto_sold_stock,
t1.related_recommend
from tb_product t1
left join (select x.product_id,
@@ -271,16 +268,4 @@
</if>
GROUP BY a.id
</select>
<update id="updateProductStockNum">
update tb_product
<if test="type == 'add'">
set stock_number = stock_number + #{num}
</if>
<if test="type == 'sub'">
set stock_number = stock_number - #{num}
</if>
where id = #{id}
and is_stock = 1
and shop_id = #{shopId}
</update>
</mapper>