45 Commits

Author SHA1 Message Date
534afeded6 交班时间 问题 2026-04-03 18:19:44 +08:00
cdde340810 订单备注 2026-04-03 18:13:08 +08:00
7d69d72aef 交班 时间 2026-04-03 18:05:42 +08:00
911feb7fe2 外带 没有餐位费 2026-04-03 17:38:30 +08:00
08a431559b 退款 操作员问题 2026-04-03 17:33:35 +08:00
48c058456d 退款单 冒号问题 2026-04-03 17:22:39 +08:00
b6eb72f260 退款总计 打印时间 订单号 2026-04-03 17:18:54 +08:00
c39640ffde 打印机 单开
支付 就餐模式
2026-04-03 16:58:35 +08:00
23b089ca90 客看单 餐位费问题 2026-04-03 16:44:51 +08:00
d112d63f43 客看单 餐位费问题 2026-04-03 16:38:30 +08:00
c8bb4d2658 第一次 2026-04-03 16:01:30 +08:00
9d267a539d 餐位费问题 2026-04-03 15:37:58 +08:00
c09e600857 餐位费问题 2026-04-03 15:33:36 +08:00
9ddfeaf1b9 交班2 2026-04-03 15:23:06 +08:00
0ada3a0466 交班 2026-04-03 15:18:07 +08:00
49babaa814 交班票 和 用餐方式 2026-04-03 15:07:23 +08:00
60fbcb32b1 用户 余额支付 2026-04-03 14:37:09 +08:00
546edea749 余额支付 2026-04-03 14:34:04 +08:00
2026022f14 退款方式 2026-04-03 14:14:56 +08:00
26927ab59d 退没的商品 不展示 2026-04-03 14:10:46 +08:00
766e5ed4de 打印 细节 2026-04-03 13:59:47 +08:00
411824ec1c 应付 不要 2026-04-03 13:46:21 +08:00
aee6293f66 支付方式 2026-04-03 13:34:25 +08:00
1d9916a7b3 操作人 置空 2026-04-03 11:48:09 +08:00
70b291c3c8 支付方式 2026-04-03 11:43:27 +08:00
365968b66c 原价 用餐人数 2026-04-03 11:38:58 +08:00
71d0252cf8 打印 3 2026-04-03 11:29:34 +08:00
f821344ab0 填充员工 2026-04-03 11:14:36 +08:00
f0a4031484 打印尝试 2 2026-04-03 11:07:25 +08:00
791096107f 打印尝试2 2026-04-02 17:43:48 +08:00
b2c102fc80 多次下单 2026-04-02 17:21:17 +08:00
acb8e38406 金额问题 2026-04-02 17:19:55 +08:00
0a1c95a276 打印2 2026-04-02 17:17:57 +08:00
fbbc6b8d30 打印 2026-04-02 16:57:12 +08:00
384557e914 数据为空 2026-04-01 14:05:06 +08:00
dcf72b07c2 交班开关 2026-04-01 13:51:48 +08:00
fb0b74a0cb 耗材 开关 2026-04-01 10:38:55 +08:00
a5fdb6eac7 金额问题 2026-03-31 16:21:09 +08:00
4484b62cee 快捷菜单 借口权限 2026-03-31 15:20:48 +08:00
cd7d23d348 订单过期 清台 2026-03-31 14:21:15 +08:00
0f2ecc5b7d 库存扣减 2026-03-31 14:11:02 +08:00
5874571200 打印声音 2026-03-31 11:43:56 +08:00
1d85cb67e1 打印声音 2026-03-31 11:41:04 +08:00
15920ce384 删除单子 清台 2026-03-30 18:14:55 +08:00
875c61adb6 删除单子 清台 2026-03-30 18:10:58 +08:00
30 changed files with 1075 additions and 583 deletions

View File

@@ -60,6 +60,31 @@ public class PrintMachineController {
return CzgResult.success(page);
}
/**
* 打印机列表
* @param name 名称
* @return 打印机列表
*/
@GetMapping("/getPrintLocal")
public CzgResult<Page<PrintMachine>> getPrintLocal(String name, String subType) {
QueryWrapper queryWrapper = new QueryWrapper().eq(PrintMachine::getShopId, StpKit.USER.getShopId());
if (StrUtil.isNotBlank(name)) {
queryWrapper.like(PrintMachine::getName, name);
}
queryWrapper.in(PrintMachine::getConnectionType, "USB", "局域网");
if (StrUtil.isNotBlank(subType)) {
queryWrapper.eq(PrintMachine::getSubType, 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);
}
/**
* 打印机详情
* @param id 打印机id

View File

@@ -29,7 +29,7 @@ public class QuickMenuController {
@Resource
private QuickMenuService quickMenuService;
@SaAdminCheckPermission(parentName = "悬浮窗", value = "quick:list", name = "悬浮窗-列表")
// @SaAdminCheckPermission(parentName = "悬浮窗", value = "quick:list", name = "悬浮窗-列表")
@GetMapping
public CzgResult<List<QuickMenu>> getQuickList(@RequestParam(required = false) Integer status,
@RequestParam(required = false, defaultValue = "0") Integer isEdit) {

View File

@@ -59,7 +59,7 @@ public class PrintMqListener {
}
Boolean printOrder = jsonObject.getBoolean("printOrder");
redisService.runFunAndCheckKey(() -> {
printerHandler.handler(orderId, printOrder != null && !printOrder ? PrinterHandler.PrintTypeEnum.ONE : PrinterHandler.PrintTypeEnum.ONE_AND_ORDER);
printerHandler.orderHandler(orderId, printOrder != null && !printOrder ? PrinterHandler.PrintTypeEnum.ONE : PrinterHandler.PrintTypeEnum.ONE_AND_ORDER, null);
return null;
}, RedisCst.getLockKey("orderPrint", orderId));
});
@@ -71,7 +71,7 @@ public class PrintMqListener {
@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.handler(data, PrinterHandler.PrintTypeEnum.HANDOVER));
printerHandler.handoverHandler(data));
}
/**
@@ -80,6 +80,6 @@ public class PrintMqListener {
@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.handler(data, PrinterHandler.PrintTypeEnum.CALL));
printerHandler.callHandler(data));
}
}

View File

@@ -1,8 +1,11 @@
package com.czg.task;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.czg.account.service.ShopTableService;
import com.czg.config.RedisCst;
import com.czg.enums.OrderNoPrefixEnum;
import com.czg.enums.ShopTableStatusEnum;
import com.czg.market.service.OrderInfoService;
import com.czg.order.entity.CashierCart;
import com.czg.order.entity.GbOrder;
@@ -19,6 +22,7 @@ import com.czg.utils.CzgRandomUtils;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -47,17 +51,24 @@ public class OTimeTask {
private PayService payService;
@Resource
private RedisService redisService;
@DubboReference
private ShopTableService shopTableService;
/**
* order 过期
*/
@Scheduled(cron = "0 0 1 * * ? ")
public void run() {
OrderInfo orderInfo = new OrderInfo();
orderInfo.setStatus(OrderStatusEnums.CANCELLED.getCode());
orderInfoService.update(orderInfo, QueryWrapper.create()
QueryWrapper queryWrapper = QueryWrapper.create()
.eq(OrderInfo::getStatus, OrderStatusEnums.UNPAID.getCode())
.lt(OrderInfo::getTradeDay, DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd")));
.lt(OrderInfo::getTradeDay, DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd"));
List<OrderInfo> list = orderInfoService.list(queryWrapper);
if (CollUtil.isNotEmpty(list)) {
list.forEach(orderInfo -> shopTableService.updateStatus(orderInfo.getShopId(), null, orderInfo.getTableCode(), ShopTableStatusEnum.IDLE.getValue()));
OrderInfo orderInfo = new OrderInfo();
orderInfo.setStatus(OrderStatusEnums.CANCELLED.getCode());
orderInfoService.update(orderInfo, queryWrapper);
}
QueryWrapper cartUpdateWrapper = new QueryWrapper();
cartUpdateWrapper.lt(CashierCart::getCreateTime, DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd HH:mm:ss"))

View File

@@ -164,6 +164,22 @@ 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();
}
/**
* 编辑副单位
*/

View File

@@ -1,13 +1,8 @@
package com.czg.account.dto.print;
import com.alibaba.fastjson2.annotation.JSONField;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.io.Serial;
import java.time.LocalDateTime;
/**
* @author Administrator
*/
@@ -94,4 +89,14 @@ public class PrinterAddDTO {
private String printType;
private Integer status;
/**
* 媒体音开关 0-关 1-开
*/
private Integer volumeSwitch;
/**
* 交班打印机开关 0-关 1-开
*/
private Integer handoverSwitch;
}

View File

@@ -1,6 +1,5 @@
package com.czg.account.dto.print;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
@@ -90,4 +89,14 @@ public class PrinterEditDTO {
* 打印机状态 online在线
*/
private String status;
/**
* 媒体音开关 0-关 1-开
*/
private Integer volumeSwitch;
/**
* 交班打印机开关 0-关 1-开
*/
private Integer handoverSwitch;
}

View File

@@ -118,5 +118,13 @@ public class PrintMachine implements Serializable {
* 打印类型JSON数组 refund-确认退款单 handover-交班单 queue-排队取号
*/
private String printType;
/**
* 媒体音开关 0-关 1-开
*/
private Integer volumeSwitch;
/**
* 交班打印机开关 0-关 1-开
*/
private Integer handoverSwitch;
}

View File

@@ -51,7 +51,7 @@ public class ShopUser implements Serializable {
/**
* 电话号码
*/
@ColumnMask(Masks.MOBILE)
// @ColumnMask(Masks.MOBILE)
private String phone;
/**

View File

@@ -25,7 +25,9 @@ public interface ShopTableService extends IService<ShopTable> {
Boolean add(Long shopId, ShopTableAddDTO shopTableAddDTO);
ShopTable getOneByTableCode(@NotNull Long shopId,@NotBlank String tableCode);
ShopTable getOneByTableCode(@NotNull Long shopId, @NotBlank String tableCode);
String getTableAreaAndName(Long shopId, String tableCode, String tableName);
void createQrCode(Long shopId, Integer num, HttpServletResponse response, HttpServletRequest request) throws IOException;
@@ -39,6 +41,7 @@ public interface ShopTableService extends IService<ShopTable> {
Boolean updateStatus(long shopId, Long tableId, String tableCode, String status);
Boolean clear(long shopId, ShopTableClearDTO shopTableClearDTO);
Boolean expiredTable(long tableId);
Page<ShopTableVO> pageInfo(Long shopId, Integer areaId, String tableCode, String status, String name, Boolean isBind);

View File

@@ -33,6 +33,11 @@ public class CheckOrderPay implements Serializable {
private boolean withCoupon = true;
private boolean withPoints = true;
/**
* 用餐模式 堂食 dine-in 外带 take-out 外卖 take-away
*/
private String dineMode;
@NotNull(message = "订单id不可为空")
private Long orderId;

View File

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

View File

@@ -37,6 +37,8 @@ public class OrderInfoRefundDTO implements Serializable {
*/
@NotNull(message = "退单金额不能为空")
private BigDecimal refundAmount;
//操作人
private String operator;
/**
* 退款金额 默认为 退单数量*单价* 订单 discount_ratio

View File

@@ -84,7 +84,7 @@ public class OrderInfoVo implements Serializable {
*/
private String orderType;
/**
* 退款方式 现金退款-cash 原路退回-payBack
* 退款方式 线下退款-cash 原路退回-payBack
*/
private String refundType;
@@ -104,7 +104,7 @@ public class OrderInfoVo implements Serializable {
* 被扫 back-scan
* 微信小程序 wechat-mini
* 支付宝小程序 alipay-mini
* 会员支付 vip-pay
* 余额支付 vip-pay
* 现金支付 cash-pay
*/
private String payType;

View File

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

View File

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

View File

@@ -87,6 +87,11 @@ public interface ConsInfoService extends IService<ConsInfo> {
*/
void onOffConsInfo(Long id, Integer isStock);
/**
* 是否退款退回
*/
void isRefundStockConsInfo(Long id, Integer isRefundStock);
/**
* 修改耗材单位
*

View File

@@ -93,14 +93,14 @@ public class AShopUserServiceImpl implements AShopUserService {
Long mainIdByShopId = shopInfoService.getMainIdByShopId(StpKit.USER.getShopId());
PageHelper.startPage(PageUtil.buildPageHelp());
PageInfo<ShopUserDTO> shopUsers = new PageInfo<>(shopUserMapper.selectPageByKeyAndIsVip(mainIdByShopId, isVip, key, amount));
shopUsers.getList().forEach(shopUserDTO -> {
if (StrUtil.isNotBlank(shopUserDTO.getPhone())) {
shopUserDTO.setPhone(DesensitizedUtil.mobilePhone(shopUserDTO.getPhone()));
}
if (StrUtil.isNotBlank(shopUserDTO.getNickName())) {
shopUserDTO.setNickName(DesensitizedUtil.chineseName(shopUserDTO.getNickName()));
}
});
// shopUsers.getList().forEach(shopUserDTO -> {
// if (StrUtil.isNotBlank(shopUserDTO.getPhone())) {
// shopUserDTO.setPhone(DesensitizedUtil.mobilePhone(shopUserDTO.getPhone()));
// }
// if (StrUtil.isNotBlank(shopUserDTO.getNickName())) {
// shopUserDTO.setNickName(DesensitizedUtil.chineseName(shopUserDTO.getNickName()));
// }
// });
return PageUtil.convert(shopUsers);
}

View File

@@ -193,7 +193,6 @@ public class AuthorizationServiceImpl implements AuthorizationService {
}
redisService.del(RedisCst.LOGIN_CODE + loginDTO.uuid());
System.out.println(StpKit.USER.getMainShopId());
return new LoginVO(StpKit.USER.getTokenInfo(), promissionList, loginDTO.loginType(), shopInfo, shopStaff);
}

View File

@@ -16,6 +16,7 @@ import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -29,7 +30,7 @@ import java.util.List;
* @author Administrator
* @since 2025-02-10
*/
@Service
@DubboService
public class ShopStaffServiceImpl extends ServiceImpl<ShopStaffMapper, ShopStaff> implements ShopStaffService {
@Resource
private SysUserService sysUserService;

View File

@@ -116,6 +116,22 @@ public class ShopTableServiceImpl extends ServiceImpl<ShopTableMapper, ShopTable
return queryChain().eq(ShopTable::getShopId, shopId).eq(ShopTable::getTableCode, tableCode).one();
}
@Override
public String getTableAreaAndName(Long shopId, String tableCode, String tableName) {
ShopTable shopTable = getOneByTableCode(shopId, tableCode);
if (shopTable == null) {
return tableName;
} else {
ShopTableArea shopArea = shopAreaService.getOne(new QueryWrapper().eq(ShopTableArea::getShopId, shopId)
.eq(ShopTableArea::getId, shopTable.getAreaId()));
if (shopArea == null) {
return tableName;
} else {
return shopArea.getName() + "-" + shopTable.getName();
}
}
}
public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit) {
response.setCharacterEncoding(request.getCharacterEncoding());
response.setContentType("application/octet-stream");

View File

@@ -50,12 +50,13 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
private final PrintSignLabel printSignLabel = new PrintSignLabel()
.setBr("<BR>")
.setCut("")
.setCut("<PCUT>")
.setOut("OUT")
.setCenterBold(new String[]{"<CB>", "</CB>"})
.setF(new String[]{"<F>", "</F>"})
.setL(new String[]{"<L>", "</L>"})
.setS(new String[]{"", ""})
.setF(new String[]{"<B>", "</B>"})
.setS(new String[]{"<s>", "</s>"})
.setS(new String[]{"<s>", "</s>"})
.setQr(new String[]{"<QR>", "</QR>"})
.setCenter(new String[]{"<C>", "</C>"})
.setBold(new String[]{"<BOLD>", "</BOLD>"});
@@ -66,99 +67,68 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
}
@Override
protected void normalDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
String remark = orderDetail.getRemark();
String content = buildDishPrintData(false, getPickupNum(orderInfo), orderInfo.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
orderDetail.getProductName(), orderDetail.getSkuName(), orderDetail.getNum(), remark, orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
String o = sendPrintRequest(machine.getAddress(), content, null, "1");
printMachineLogService.save(orderInfo.getId(), machine, "新订单", content, o);
}
@Override
protected void returnDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
String remark = orderDetail.getRemark();
String content = buildDishPrintData(true, getPickupNum(orderInfo), orderInfo.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
orderDetail.getProductName(), orderDetail.getSkuName(), orderDetail.getReturnNum(), remark, orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
String o = sendPrintRequest(machine.getAddress(), content, null, "1");
printMachineLogService.save(orderInfo.getId(), machine, "退款单", content, o);
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 returnOrderPrint(OrderInfo orderInfo, PrintMachine machine, String balance, List<OrderDetail> detailList) {
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
String printerNum = "1";
if (StrUtil.isNotBlank(machine.getPrintQty())) {
printerNum = machine.getPrintQty().split("\\^")[1];
}
PrintInfoDTO printInfoDTO = new PrintInfoDTO().setShopName(shopInfo.getShopName())
.setPrintType("普通打印").setPickupNum(getPickupNum(orderInfo))
.setOrderNo(orderInfo.getOrderNo())
.setTradeDate(DateUtil.format(orderInfo.getCreateTime(), "yyyy-MM-dd HH:mm:ss"))
.setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
.setOriginalAmount((orderInfo.getOriginAmount().add(orderInfo.getSeatAmount()).add(orderInfo.getPackFee())).toPlainString())
.setReturn(isReturn(orderInfo))
.setBalance(balance)
.setPayType((ObjectUtil.isEmpty(orderInfo.getPayType()) || ObjectUtil.isNull(orderInfo.getPayType()) ? "" : orderInfo.getPayType()))
.setIntegral("0")
.setOutNumber(orderInfo.getTakeCode())
.setPrintTitle("结算单")
.setRemark(orderInfo.getRemark())
// 使用累计的总优惠金额,如果为 null 则用原价减去实付计算
.setDiscountAmount(calculateDiscountAmount(orderInfo));
if (orderInfo.getPayAmount() != null && orderInfo.getPayAmount().compareTo(BigDecimal.ZERO) == 0) {
// 设置支付金额为 订单原价-订单优惠金额
printInfoDTO.setPayAmount((new BigDecimal(printInfoDTO.getOriginalAmount()).subtract(new BigDecimal(printInfoDTO.getDiscountAmount()))).toPlainString());
}
String string = buildOrderPrintData(printInfoDTO, detailList);
String o = sendPrintRequest(machine.getAddress(), string, null, printerNum);
printMachineLogService.save(orderInfo.getId(), machine, "结算单", string, o);
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
protected void normalOrderPrint(OrderInfo orderInfo, boolean isPre, PrintMachine machine, String balance, List<OrderDetail> detailList) {
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
long count = orderInfoService.queryChain()
.eq(OrderInfo::getTradeDay, orderInfo.getTradeDay())
.eq(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode())
.eq(OrderInfo::getShopId, orderInfo.getShopId())
.le(OrderInfo::getCreateTime, orderInfo.getCreateTime()).count();
String printerNum = "1";
if (StrUtil.isNotBlank(machine.getPrintQty())) {
printerNum = machine.getPrintQty().split("\\^")[1];
}
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;
}
PrintInfoDTO printInfoDTO = new PrintInfoDTO().setShopName(shopInfo.getShopName())
.setCount(count)
.setPrintType("普通打印").setPickupNum(getPickupNum(orderInfo))
.setOrderNo(orderInfo.getOrderNo()).setTradeDate(DateUtil.format(orderInfo.getCreateTime(), "yyyy-MM-dd HH:mm:ss")).setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
.setOriginalAmount((orderInfo.getOriginAmount().add(orderInfo.getSeatAmount()).add(orderInfo.getPackFee())).toPlainString()).setReturn(isReturn(orderInfo))
.setBalance(balance).setPayType((ObjectUtil.isEmpty(orderInfo.getPayType()) || ObjectUtil.isNull(orderInfo.getPayType()) ? "" : orderInfo.getPayType())).setIntegral("0")
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle("结算单")
.setRemark(orderInfo.getRemark())
// 使用累计的总优惠金额,如果为 null 则用原价减去实付计算
.setDiscountAmount(calculateDiscountAmount(orderInfo));
printInfoDTO.setPrintTitle(printInfoDTO.getPrintTitle());
if (orderInfo.getSeatNum() != null && orderInfo.getSeatAmount().compareTo(BigDecimal.ZERO) > 0) {
printInfoDTO.setSeatNum(orderInfo.getSeatNum().toString());
printInfoDTO.setSeatAmount(orderInfo.getSeatAmount().toPlainString());
}
if (orderInfo.getPackFee().compareTo(BigDecimal.ZERO) > 0) {
printInfoDTO.setPackFee(orderInfo.getPackFee().toPlainString());
}
@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;
}
String string = buildOrderPrintData(printInfoDTO, detailList);
String resp = sendPrintRequest(machine.getAddress(), string, null, printerNum);
printMachineLogService.save(orderInfo.getId(), machine, "结算单", string, resp);
@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 voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一条新的排号记录\"}";
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
if (1 == machine.getVolumeSwitch()) {
voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一条新的排号记录\"}";
}
String data = buildCallTicketData(shopName, tableName, callNum, preNum, codeUrl, shopNote, takeTime);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, "1");
printMachineLogService.save(machine, "叫号单", data, resp);
@@ -178,6 +148,19 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
return DigestUtils.sha1Hex(FeiPrinter.USER + FeiPrinter.UKEY + timeStamp);
}
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);
}
@Override
public String sendPrintRequest(String address, String metaPrintData, String voiceData, String printerNum) {
log.info("飞蛾打印机开始发送打印请求, 设备地址: {}, 元数据: {}", address, metaPrintData);

View File

@@ -1,7 +1,7 @@
package com.czg.service.order.print;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
@@ -37,6 +37,7 @@ import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@@ -73,6 +74,10 @@ public abstract class PrinterHandler {
@DubboReference
protected ShopInfoService shopInfoService;
@DubboReference
private ShopTableService shopTableService;
@DubboReference
private ShopStaffService shopStaffService;
@DubboReference
protected ProductService productService;
@DubboReference
protected ProdSkuService prodSkuService;
@@ -84,11 +89,17 @@ public abstract class PrinterHandler {
@Getter
public enum PrintTypeEnum {
HANDOVER("交班", "handover"),
ORDER("订单", "order"),
ONE("菜品", "one"),
CALL("叫号", "call"),
ONE_AND_ORDER("菜品和结算单同时打印", "oneAndOrder"),
PRE_ORDER("预结算单", "preOrder");
PRE_ORDER("预结算单", "preOrder"),
ORDER("订单结算单", "order"),
GUEST_ORDER("客看单", "guestOrder"),
RETURN_FOOD("退菜", "returnFood"),
RETURN_ORDER("退单", "returnOrder"),
ONE("菜品", "one"),
CALL("叫号", "call");
private final String name;
private final String code;
@@ -113,29 +124,40 @@ public abstract class PrinterHandler {
@Accessors(chain = true)
public static class PrintInfoDTO {
private long count;
// 打印标题 退款单/结算单
// 打印标题 结算单/客看单/结算单 退菜单/退款单
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 balance;
//余额
// private String balance;
private String payType;
private String integral;
private String remark;
//取餐码
private String outNumber;
private String discountAmount;
private String discountRadio;
private String orderNum;
// private String discountRadio;
// private String orderNum;
private String seatNum;
private String seatAmount;
private String packFee;
// 是否退款单
private boolean isReturn;
//退款单用
private String refundAmount;
//退款方式 现金退款/原路退回
private String refundType;
//退款原因
private String refundReason;
}
@@ -187,96 +209,111 @@ public abstract class PrinterHandler {
}
/**
* 处理打印
* 处理订单打印
*
* @param data 传递的数据
* @param printTypeEnum order returnOrder preOrder one call handover
* @param printTypeEnum order preOrder one
*/
public void handler(String data, PrintTypeEnum printTypeEnum) {
Long shopId;
String printMethod = "";
String printType = "";
Object obj;
OrderInfo orderInfo;
public void orderHandler(String data, PrintTypeEnum printTypeEnum, Integer placeNum) {
String printMethod;
OrderInfo orderInfo = orderInfoService.getById(data);
if (orderInfo == null) {
throw new RuntimeException("订单打印失败,订单不存在");
}
switch (printTypeEnum) {
case PrintTypeEnum.HANDOVER:
HandoverRecordDTO record = handoverRecordService.getHandoverRecordById(Long.parseLong(data));
if (record == null) {
throw new RuntimeException("交班票打印失败,交班记录不存在");
}
obj = record;
shopId = record.getShopId();
printType = "handover";
break;
case PrintTypeEnum.GUEST_ORDER:
case PrintTypeEnum.PRE_ORDER:
case PrintTypeEnum.ORDER:
orderInfo = orderInfoService.getById(data);
if (orderInfo == null) {
throw new RuntimeException("订单打印失败,订单不存在");
}
obj = orderInfo;
shopId = orderInfo.getShopId();
printMethod = "normal";
break;
case PrintTypeEnum.ONE:
orderInfo = orderInfoService.getById(data);
if (orderInfo == null) {
throw new RuntimeException("订单打印失败,订单不存在");
}
shopId = orderInfo.getShopId();
obj = orderInfo;
printMethod = "one";
break;
case PrintTypeEnum.PRE_ORDER:
orderInfo = orderInfoService.getById(data);
if (orderInfo == null) {
throw new RuntimeException("订单打印失败,订单不存在");
}
shopId = orderInfo.getShopId();
obj = orderInfo;
printMethod = "normal";
break;
case PrintTypeEnum.ONE_AND_ORDER:
orderInfo = orderInfoService.getById(data);
if (orderInfo == null) {
throw new RuntimeException("订单打印失败,订单不存在");
}
shopId = orderInfo.getShopId();
obj = orderInfo;
printMethod = "all";
break;
case PrintTypeEnum.CALL:
CallQueue queue = callQueueService.getById(data);
if (queue == null) {
throw new RuntimeException("叫号信息不存在: " + data);
}
shopId = queue.getShopId();
obj = queue;
printType = "queue";
break;
default:
throw new RuntimeException("未知打印类型");
}
if (shopId == null) {
throw new RuntimeException("店铺不存在, id:" + shopId);
}
Object finalObj = obj;
getPrintMachine(shopId, "cash", printMethod, printType).forEach(machine -> {
handleRequest(machine, finalObj, printTypeEnum);
// printPlaceTicket(isReturn, machine, orderInfo, shopInfo);
getPrintMachine(orderInfo.getShopId(), "cash", printMethod, "").forEach(machine -> {
handleRequest(machine, placeNum, orderInfo, printTypeEnum);
});
}
private void handleRequest(PrintMachine machine, Object data, PrintTypeEnum printTypeEnum) {
/**
* 处理退菜退款订单打印
*
* @param printTitle 退菜单 / 退款单
* @param operator 操作人
* @param refundAmount 退款金额
* @param refundReason 退款原因
* @param refundType 退款方式
* @param orderInfo 订单信息
* @param detailList 退菜/退款 列表
*/
public void refundOrderHandler(String printTitle, String operator, String refundAmount, String refundReason, String refundType,
OrderInfo orderInfo, List<OrderDetail> detailList) {
getPrintMachine(orderInfo.getShopId(), "cash", "normal", "").forEach(machine -> {
orderInfo.setTableName(getTableAreaAndName(orderInfo.getShopId(), orderInfo.getTableCode(), orderInfo.getTableName()));
refundHandleRequest(machine, printTitle, operator, refundAmount, refundReason, refundType, orderInfo, detailList);
});
}
/**
* 叫号打印
*
* @param data 传递的数据
*/
public void callHandler(String data) {
CallQueue queue = callQueueService.getById(data);
if (queue == null) {
throw new RuntimeException("叫号信息不存在: " + data);
}
Long shopId = queue.getShopId();
if (shopId == null) {
throw new RuntimeException("店铺不存在, id:" + shopId);
}
getPrintMachine(shopId, "cash", "", "queue").forEach(machine -> handleRequest(machine, null, queue, PrintTypeEnum.CALL));
}
/**
* 交班打印
*
* @param data 传递的数据
*/
public void handoverHandler(String data) {
HandoverRecordDTO record = handoverRecordService.getHandoverRecordById(Long.parseLong(data));
if (record == null) {
throw new RuntimeException("交班票打印失败,交班记录不存在");
}
Long shopId = record.getShopId();
if (shopId == null) {
throw new RuntimeException("店铺不存在, id:" + shopId);
}
getPrintMachine(shopId, "cash", "", "handover").forEach(machine -> handleRequest(machine, null, record, PrintTypeEnum.HANDOVER));
}
private void handleRequest(PrintMachine machine, Integer placeNum, Object data, PrintTypeEnum printTypeEnum) {
if (canHandleRequest(machine.getContentType(), machine.getConnectionType())) {
log.info("打印机: {}, 传递信息: {}", machine.getName(), data);
print(machine, data, printTypeEnum);
print(machine, placeNum, data, printTypeEnum);
} else if (nextPrinter != null) {
log.info("当前打印机无法处理: {},将请求传递给下一个打印机:{}...", this.printerBrand, nextPrinter.printerBrand);
nextPrinter.handleRequest(machine, data, printTypeEnum);
nextPrinter.handleRequest(machine, placeNum, data, printTypeEnum);
} else {
log.warn("未找到匹配打印机");
}
}
private void refundHandleRequest(PrintMachine machine, String printTitle, String operator, String refundAmount, String refundReason, String refundType,
OrderInfo orderInfo, List<OrderDetail> detailList) {
if (canHandleRequest(machine.getContentType(), machine.getConnectionType())) {
log.info("退款打印机: {}, 传递信息: {}", machine.getName(), orderInfo.getId());
returnOrderPrint(printTitle, operator, refundAmount, refundReason, refundType, orderInfo, machine, detailList);
} else if (nextPrinter != null) {
log.info("当前打印机无法处理: {},将请求传递给下一个打印机:{}...", this.printerBrand, nextPrinter.printerBrand);
nextPrinter.refundHandleRequest(machine, printTitle, operator, refundAmount, refundReason, refundType, orderInfo, detailList);
} else {
log.warn("未找到匹配打印机");
}
@@ -329,7 +366,7 @@ public abstract class PrinterHandler {
}
protected void print(PrintMachine machine, Object data, PrintTypeEnum printTypeEnum) {
protected void print(PrintMachine machine, Integer placeNum, Object data, PrintTypeEnum printTypeEnum) {
switch (printTypeEnum) {
case PrintTypeEnum.HANDOVER:
log.info("准备开始打印交班");
@@ -339,12 +376,22 @@ public abstract class PrinterHandler {
throw new RuntimeException("传递数据类型有误");
}
break;
case PrintTypeEnum.GUEST_ORDER:
log.info("准备开始打印客看订单");
if (data instanceof OrderInfo orderInfo) {
orderInfo.setPlaceNum(placeNum);
List<OrderDetail> orderDetailList = orderDetailService.list(new QueryWrapper().eq(OrderDetail::getOrderId, orderInfo.getId()).eq(OrderDetail::getPlaceNum, placeNum));
guestOrderPrint(orderInfo, machine, orderDetailList);
} else {
throw new RuntimeException("传递数据类型有误");
}
break;
case PrintTypeEnum.ORDER:
log.info("准备开始打印订单");
if (data instanceof OrderInfo orderInfo) {
redisService.set("order:print:" + orderInfo.getId(),"", 180);
redisService.set("order:print:" + orderInfo.getId(), "", 180);
List<OrderDetail> orderDetailList = orderDetailService.list(new QueryWrapper().eq(OrderDetail::getOrderId, orderInfo.getId()));
onlyFrontDesk(machine, false, orderInfo, orderDetailList);
orderPrint(machine, orderInfo, orderDetailList);
} else {
throw new RuntimeException("传递数据类型有误");
}
@@ -352,9 +399,9 @@ public abstract class PrinterHandler {
case PrintTypeEnum.PRE_ORDER:
log.info("准备开始打印预结算订单");
if (data instanceof OrderInfo orderInfo) {
redisService.set("order:print:" + orderInfo.getId(),"", 180);
redisService.set("order:print:" + orderInfo.getId(), "", 180);
List<OrderDetail> orderDetailList = orderDetailService.list(new QueryWrapper().eq(OrderDetail::getOrderId, orderInfo.getId()));
onlyFrontDesk(machine, true, orderInfo, orderDetailList);
preOrderPrint(machine, orderInfo, orderDetailList);
} else {
throw new RuntimeException("传递数据类型有误");
}
@@ -362,7 +409,7 @@ public abstract class PrinterHandler {
case PrintTypeEnum.ONE:
log.info("准备开始打印菜品单");
if (data instanceof OrderInfo orderInfo) {
redisService.set("order:print:" + orderInfo.getId(),"", 180);
redisService.set("order:print:" + orderInfo.getId(), "", 180);
List<OrderDetail> orderDetailList = orderDetailService.list(new QueryWrapper().eq(OrderDetail::getOrderId, orderInfo.getId()));
onlyKitchen(machine, orderInfo, orderDetailList);
} else {
@@ -380,11 +427,11 @@ public abstract class PrinterHandler {
case PrintTypeEnum.ONE_AND_ORDER:
log.info("准备开始打印菜品以及结算单");
if (data instanceof OrderInfo orderInfo) {
redisService.set("order:print:" + orderInfo.getId(),"", 180);
redisService.set("order:print:" + orderInfo.getId(), "", 180);
List<OrderDetail> orderDetailList = orderDetailService.list(new QueryWrapper().eq(OrderDetail::getOrderId, orderInfo.getId()));
switch (machine.getPrintMethod()) {
case "all":
onlyFrontDesk(machine, false, orderInfo, orderDetailList);
orderPrint(machine, orderInfo, orderDetailList);
onlyKitchen(machine, orderInfo, orderDetailList);
break;
case "one":
@@ -393,7 +440,7 @@ public abstract class PrinterHandler {
break;
case "normal":
log.info("打印机仅打印normal");
onlyFrontDesk(machine, false, orderInfo, orderDetailList);
orderPrint(machine, orderInfo, orderDetailList);
break;
default:
throw new RuntimeException("打印方法有误");
@@ -413,7 +460,6 @@ public abstract class PrinterHandler {
// 判断订单是否是先付费或者已结算
if (!"after-pay".equals(orderInfo.getPayMode()) && (OrderStatusEnums.UNPAID.getCode().equals(orderInfo.getStatus()) || OrderStatusEnums.CANCELLED.getCode().equals(orderInfo.getStatus()))) {
log.warn("此订单未支付, 订单信息: {}", orderInfo);
// return;
}
List<?> categoryIds = JSONObject.parseObject(StrUtil.emptyToDefault(machine.getCategoryIds(), "[]"), List.class);
@@ -429,7 +475,6 @@ public abstract class PrinterHandler {
if (item.getNum().compareTo(BigDecimal.ZERO) <= 0 && item.getReturnNum().compareTo(BigDecimal.ZERO) <= 0) {
return;
}
log.info("开始打印菜品,商品名:{}", item.getProductName());
Integer isWaitCall = ObjectUtil.defaultIfNull(item.getIsWaitCall(), 0);
if (isWaitCall == 1) {
if (!item.getProductName().contains("【等叫】")) {
@@ -455,11 +500,11 @@ public abstract class PrinterHandler {
}
if (item.getReturnNum().compareTo(BigDecimal.ZERO) > 0) {
returnDishesPrint(orderInfo, item, machine);
returnDishesPrint("操作人名称", orderInfo, item, machine);
}
if (item.getNum().compareTo(BigDecimal.ZERO) > 0) {
normalDishesPrint(orderInfo, item, machine);
normalDishesPrint("操作人名称", orderInfo, item, machine);
}
// 保存已打印信息
@@ -472,10 +517,60 @@ public abstract class PrinterHandler {
}
/**
* 打印预结算单「前台」
*/
private void preOrderPrint(PrintMachine machine, OrderInfo orderInfo, List<OrderDetail> orderDetail) {
// 判断订单是否是先付费或者已结算
if (OrderStatusEnums.CANCELLED.getCode().equals(orderInfo.getStatus())) {
log.warn("已取消, 订单信息: {}", orderInfo);
}
if (orderDetail.isEmpty()) {
log.info("待打印列表为空");
return;
}
List<PrintOrderDetailDTO> detailList = new ArrayList<>();
orderDetail.forEach(it -> {
Integer isTemporary = ObjectUtil.defaultIfNull(it.getIsTemporary(), 0);
String remark = "";
if (isTemporary == 0) {
ProdSku prodSku = prodSkuService.getById(it.getSkuId());
if (ObjectUtil.isNotEmpty(prodSku) && ObjectUtil.isNotEmpty(prodSku.getSpecInfo())) {
remark = prodSku.getSpecInfo();
}
}
Integer isWaitCall = ObjectUtil.defaultIfNull(it.getIsWaitCall(), 0);
if (isWaitCall == 1) {
it.setProductName("【等叫】%s".formatted(it.getProductName()));
}
if (isTemporary == 1) {
it.setProductName("【临】%s".formatted(it.getProductName()));
}
it.setPackAmount(it.getPackAmount() == null ? BigDecimal.ZERO : it.getPackAmount());
boolean isGift = it.getIsGift() != null && it.getIsGift() == 1;
if (isGift) {
it.setProductName("【赠】%s".formatted(it.getProductName()));
}
BigDecimal unitPrice = it.getPrice();
if (isGift) {
unitPrice = BigDecimal.ZERO;
}
PrintOrderDetailDTO detail = new PrintOrderDetailDTO(it.getProductName(), it.getNum().toString(), unitPrice.stripTrailingZeros().toPlainString(), remark, it.getProGroupInfo());
detailList.add(detail);
});
if (!detailList.isEmpty()) {
preOrderPrint(orderInfo, machine, orderDetail);
}
}
/**
* 仅打印结算单「前台」
*/
private void onlyFrontDesk(PrintMachine machine, boolean isPre, OrderInfo orderInfo, List<OrderDetail> tbOrderDetailList) {
private void orderPrint(PrintMachine machine, OrderInfo orderInfo, List<OrderDetail> tbOrderDetailList) {
// 判断订单是否是先付费或者已结算
if (OrderStatusEnums.UNPAID.getCode().equals(orderInfo.getStatus()) || OrderStatusEnums.CANCELLED.getCode().equals(orderInfo.getStatus())) {
log.warn("此订单未支付或已取消, 订单信息: {}", orderInfo);
@@ -514,23 +609,9 @@ public abstract class PrinterHandler {
}
PrintOrderDetailDTO detail = new PrintOrderDetailDTO(it.getProductName(), it.getNum().toString(), unitPrice.stripTrailingZeros().toPlainString(), remark, it.getProGroupInfo());
detailList.add(detail);
});
String balance = "0";
if ("deposit".equals(orderInfo.getPayType())) {
ShopUser user = shopUserService.getOne(new QueryWrapper().eq(ShopUser::getSourceShopId, orderInfo.getShopId()).eq(ShopUser::getUserId, orderInfo.getUserId()));
if (ObjectUtil.isNotEmpty(user) && ObjectUtil.isNotEmpty(user.getAmount())) {
balance = user.getAmount().toPlainString();
}
}
if (!detailList.isEmpty()) {
if (isReturn(orderInfo)) {
returnOrderPrint(orderInfo, machine, balance, tbOrderDetailList);
} else {
normalOrderPrint(orderInfo, isPre, machine, balance, tbOrderDetailList);
}
orderPrint(orderInfo, machine, tbOrderDetailList);
}
}
@@ -567,36 +648,175 @@ public abstract class PrinterHandler {
return StrUtil.isBlank(orderInfo.getTableName()) ? orderInfo.getTakeCode() : orderInfo.getTableName();
}
/**
* 根据订单信息判断是否是退单
*
* @param orderInfo 顶动感信息
* @return 是否退款
*/
protected static boolean isReturn(OrderInfo orderInfo) {
return ArrayUtil.contains(new String[]{"refunding", "part_refund", "refund"}, orderInfo.getStatus());
public String getTableAreaAndName(Long shopId, String tableCode, String tableName) {
return shopTableService.getTableAreaAndName(shopId, tableCode, tableName);
}
public PrintInfoDTO returnOrderPrint(String printTitle, String operator, String refundAmount, String refundReason, String refundType,
OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
PrintInfoDTO printInfoDTO = new PrintInfoDTO().setShopName(shopInfo.getShopName()).setPrintType("收银-堂食")
.setOrderNo(orderInfo.getOrderNo())
.setTradeDate(DateUtil.format(orderInfo.getCreateTime(), "yyyy/MM/dd HH:mm:ss"))
.setOperator(operator)
.setReturn(true)
.setPrintTitle(printTitle);
printInfoDTO.setSeatNum(orderInfo.getSeatNum() == null ? "" : orderInfo.getSeatNum().toString());
printInfoDTO.setPickupNum(getTableAreaAndName(orderInfo.getShopId(), orderInfo.getTableCode(), orderInfo.getTableName()));
printInfoDTO.setRefundAmount(refundAmount);
printInfoDTO.setRefundReason(refundReason);
printInfoDTO.setRefundType("cash".equals(refundType) ? "线下退款" : "原路退回");
return printInfoDTO;
}
public PrintInfoDTO guestOrderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
PrintInfoDTO printInfoDTO = getPrintInfoDTO(orderInfo, "客看单");
BigDecimal originalAmount = BigDecimal.ZERO;
for (OrderDetail orderDetail : detailList) {
if (orderDetail.getIsGift() == 1) {
} else if (orderDetail.getDiscountSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
originalAmount = originalAmount.add((orderDetail.getNum().subtract(orderDetail.getReturnNum()).subtract(orderDetail.getRefundNum())).multiply(orderDetail.getUnitPrice()));
} else {
originalAmount = originalAmount.add((orderDetail.getNum().subtract(orderDetail.getReturnNum()).subtract(orderDetail.getRefundNum())).multiply(orderDetail.getPrice()));
}
Integer isTemporary = ObjectUtil.defaultIfNull(orderDetail.getIsTemporary(), 0);
Integer isWaitCall = ObjectUtil.defaultIfNull(orderDetail.getIsWaitCall(), 0);
if (isWaitCall == 1) {
orderDetail.setProductName("【等叫】%s".formatted(orderDetail.getProductName()));
}
if (isTemporary == 1) {
orderDetail.setProductName("【临】%s".formatted(orderDetail.getProductName()));
}
orderDetail.setPackAmount(orderDetail.getPackAmount() == null ? BigDecimal.ZERO : orderDetail.getPackAmount());
boolean isGift = orderDetail.getIsGift() != null && orderDetail.getIsGift() == 1;
if (isGift) {
orderDetail.setProductName("【赠】%s".formatted(orderDetail.getProductName()));
}
}
log.info("客看单 第{}次下单--------------------------------------------", orderInfo.getPlaceNum());
if (orderInfo.getPlaceNum() != null && orderInfo.getPlaceNum() != 1) {
orderInfo.setSeatAmount(BigDecimal.ZERO);
printInfoDTO.setSeatAmount("");
}
printInfoDTO.setOriginalAmount((originalAmount.add(orderInfo.getSeatAmount()).add(orderInfo.getPackFee()))
.setScale(2, RoundingMode.HALF_UP).toPlainString());
printInfoDTO.setPayAmount((originalAmount.add(orderInfo.getSeatAmount()).add(orderInfo.getPackFee())
.subtract(orderInfo.getDiscountAllAmount())).setScale(2, RoundingMode.HALF_UP).toPlainString());
if (orderInfo.getPackFee().compareTo(BigDecimal.ZERO) > 0) {
printInfoDTO.setPackFee(orderInfo.getPackFee().toPlainString());
}
return printInfoDTO;
}
public PrintInfoDTO preOrderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
PrintInfoDTO printInfoDTO = getPrintInfoDTO(orderInfo, "预结算单");
BigDecimal originalAmount = BigDecimal.ZERO;
for (OrderDetail orderDetail : detailList) {
if (orderDetail.getIsGift() == 1) {
continue;
} else if (orderDetail.getDiscountSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
originalAmount = originalAmount.add((orderDetail.getNum().subtract(orderDetail.getReturnNum()).subtract(orderDetail.getRefundNum())).multiply(orderDetail.getUnitPrice()));
} else {
originalAmount = originalAmount.add((orderDetail.getNum().subtract(orderDetail.getReturnNum()).subtract(orderDetail.getRefundNum())).multiply(orderDetail.getPrice()));
}
}
printInfoDTO.setOriginalAmount((originalAmount.add(orderInfo.getSeatAmount()).add(orderInfo.getPackFee()))
.setScale(2, RoundingMode.HALF_UP).toPlainString());
printInfoDTO.setPayAmount(originalAmount.add(orderInfo.getSeatAmount()).add(orderInfo.getPackFee())
.subtract(orderInfo.getDiscountAllAmount()).setScale(2, RoundingMode.HALF_UP).toPlainString());
if (orderInfo.getPackFee().compareTo(BigDecimal.ZERO) > 0) {
printInfoDTO.setPackFee(orderInfo.getPackFee().toPlainString());
}
return printInfoDTO;
}
public PrintInfoDTO orderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
PrintInfoDTO printInfoDTO = getPrintInfoDTO(orderInfo, "结算单");
BigDecimal originalAmount = orderInfo.getOriginAmount() == null ? BigDecimal.ZERO : orderInfo.getOriginAmount();
printInfoDTO.setOriginalAmount(originalAmount.toPlainString());
printInfoDTO.setPayAmount(originalAmount.subtract(orderInfo.getDiscountAllAmount()).setScale(2, RoundingMode.HALF_UP).toPlainString());
if (orderInfo.getPackFee().compareTo(BigDecimal.ZERO) > 0) {
printInfoDTO.setPackFee(orderInfo.getPackFee().toPlainString());
}
return printInfoDTO;
}
private PrintInfoDTO getPrintInfoDTO(OrderInfo orderInfo, String printTitle) {
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
long count = orderInfoService.count(new QueryWrapper().eq(OrderInfo::getTradeDay, orderInfo.getTradeDay())
.eq(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode())
.eq(OrderInfo::getShopId, orderInfo.getShopId())
.le(OrderInfo::getCreateTime, orderInfo.getCreateTime()));
PrintInfoDTO printInfoDTO = new PrintInfoDTO().setShopName(shopInfo.getShopName())
.setPrintTitle(printTitle)
.setPickupNum(getTableAreaAndName(orderInfo.getShopId(), orderInfo.getTableCode(), orderInfo.getTableName()))
.setOrderNo(orderInfo.getOrderNo()).setPayAmount(orderInfo.getPayAmount().toPlainString()).setReturn(false)
.setOutNumber(orderInfo.getTakeCode()).setCount(count).setRemark(orderInfo.getRemark())
// 使用累计的总优惠金额null 表示没有优惠
.setDiscountAmount(orderInfo.getDiscountAllAmount() != null
? orderInfo.getDiscountAllAmount().toPlainString()
: "0.00");
printInfoDTO.setSeatNum(orderInfo.getSeatNum() == null ? "" : orderInfo.getSeatNum().toString());
if (orderInfo.getSeatNum() != null && orderInfo.getSeatAmount().compareTo(BigDecimal.ZERO) > 0) {
printInfoDTO.setSeatAmount(orderInfo.getSeatAmount().divide(BigDecimal.valueOf(orderInfo.getSeatNum()), 2, RoundingMode.DOWN).toPlainString());
}
if (StrUtil.isNotBlank(orderInfo.getDineMode())) {
switch (orderInfo.getDineMode()) {
case "dine-in" -> printInfoDTO.setPrintType("收银-堂食");
case "take-out" -> printInfoDTO.setPrintType("收银-外带");
case "take-away" -> printInfoDTO.setPrintType("收银-外卖");
}
if (!"dine-in".equals(orderInfo.getDineMode())) {
orderInfo.setSeatAmount(BigDecimal.ZERO);
printInfoDTO.setSeatAmount("");
}
}
if (orderInfo.getStaffId() != null) {
ShopStaff detail = shopStaffService.getOne(new QueryWrapper().eq(ShopStaff::getId, orderInfo.getStaffId()).eq(ShopStaff::getShopId, orderInfo.getShopId()));
if (detail != null) {
printInfoDTO.setOperator(detail.getName());
} else {
printInfoDTO.setOperator("");
}
} else {
printInfoDTO.setOperator("");
}
if ("结算单".equals(printTitle)) {
if (StrUtil.isNotBlank(orderInfo.getPayType())) {
switch (orderInfo.getPayType()) {
case "main_scan" -> printInfoDTO.setPayType("二维码收款");
case "back_scan" -> printInfoDTO.setPayType("扫码收款");
case "wechat_mini" -> printInfoDTO.setPayType("微信小程序");
case "alipay_mini" -> printInfoDTO.setPayType("支付宝小程序");
case "vip_pay" -> printInfoDTO.setPayType("余额支付");
case "cash_pay" -> printInfoDTO.setPayType("现金支付");
case "credit_pay" -> printInfoDTO.setPayType("挂账支付");
case "free_pay" -> printInfoDTO.setPayType("霸王餐支付");
}
}
printInfoDTO.setTradeDate(DateUtil.format(orderInfo.getPaidTime(), "yyyy/MM/dd HH:mm:ss"));
}
return printInfoDTO;
}
/**
* 菜品打印
*/
protected abstract void normalDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine);
protected abstract void normalDishesPrint(String operator, OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine);
/**
* 菜品 退菜打印
*/
protected abstract void returnDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine);
/**
* 退单打印
*/
protected abstract void returnOrderPrint(OrderInfo orderInfo, PrintMachine machine, String balance, List<OrderDetail> detailList);
/**
* 订单打印
*/
protected abstract void normalOrderPrint(OrderInfo orderInfo, boolean isPre, PrintMachine machine, String balance, List<OrderDetail> detailList);
protected abstract void returnDishesPrint(String operator, OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine);
/**
* 叫号打印

View File

@@ -1,5 +1,6 @@
package com.czg.service.order.print;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.NumberUtil;
@@ -18,6 +19,7 @@ import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* 打印机具体打印方法接口,提供打印元数据获取,具体打印机实现对应方法即可
@@ -28,11 +30,39 @@ public interface PrinterImpl {
@Data
@Accessors(chain = true)
class PrintSignLabel {
/**
* <BR> :换行符
* <CUT> :切刀指令/自动走纸(主动切纸,仅限切刀打印机使用才有效果/手动撕纸设备使用该指令时为自动走纸)
* <LOGO> 打印LOGO指令(有该指令则会打印LOGO设备首次使用需上传LOGO图片)
* <PLUGIN> :预留
* <S></S>缩小字体对应24*24字体默认字体大小为32*32
* <F></F>放大字体对应48*48字体
* <CB></CB>设置字体64*64且居中
* <B></B>放大一倍对应64*64字体
* <C></C>:居中
* <L></L>:字体变高一倍
* <W></W>:字体变宽一倍
* <QR></QR>:二维码(单个订单,最多只能打印一个二维码)
* <BC128_A></BC128_A>:数字字母混合条形码
* <RIGHT></RIGHT>:右对齐
* <BOLD></BOLD>:字体加粗
* <UDL></UDL>: 设置下划线打印
* <HL></HL>: 反白打印
* <RT:?></RT>: 字符旋转(“?”代表旋转角度)
* <RS:?>: 此行到下行的行间距“?”该值可自己设置最小1最大127不设置则为默认
* <WS:?>: 每行中文字的间距“?”该值可自己设置最小1最大48不设置则为默认
* <CS:x>:设置可变字体大小</CS>x16,24,32,48,64,72,96都可支持如x=96则为96*96字体
* <OUT:113>:走纸113点
* <PLUGIN>:切刀全切指令(只适用带切刀型设备)
* <PCUT>:切刀半切指令(只适用带切刀型设备)
*/
private String[] center;
private String[] centerBold;
private String[] bold;
private String br;
//f 的行数字符为 30
private String[] s;
//f 的行数字符为 14
private String[] f;
private String[] l;
private String[] qr;
@@ -108,7 +138,6 @@ public interface PrinterImpl {
// 品名可以在一行显示,直接补足空格
title = titleAddSpace(title, b1);
sb.append(getFormatLabel(title + otherStr, signLabelInfo.s));
// sb.append(startSplitSign).append(title).append(otherStr).append(endSplitSign);
} else {
// 品名超出一行,进行拆分
List<String> lines = isEn(title)
@@ -119,22 +148,16 @@ public interface PrinterImpl {
// 第一行拼接其它字段
String firstLine = titleAddSpace(lines.getFirst(), b1);
// sb.append(startSplitSign).append(firstLine).append(otherStr).append(endSplitSign).append("<BR>");
sb.append(getFormatLabel(firstLine + otherStr, signLabelInfo.s));
sb.append(signLabelInfo.br);
// 剩余的行单独换行输出
for (int i = 1; i < lines.size(); i++) {
if (i+1 != lines.size()) {
// sb.append(signLabelInfo.getRs(1));
if (i + 1 != lines.size()) {
sb.append(getFormatLabel(titleAddSpace(lines.get(i), b1), signLabelInfo.s));
sb.append(signLabelInfo.br);
}else {
} else {
sb.append(getFormatLabel(titleAddSpace(lines.get(i), b1), signLabelInfo.s));
}
// sb.append(startSplitSign).append(lines.get(i)).append(endSplitSign).append("BR>");
}
}
sb.append(signLabelInfo.br);
@@ -157,21 +180,34 @@ public interface PrinterImpl {
default String buildHandoverData(HandoverRecordDTO handoverRecord) {
PrintSignLabel signLabelInfo = getSignLabelInfo();
StringBuilder builder = new StringBuilder()
.append(getFormatLabel(handoverRecord.getShopName(), signLabelInfo.center, signLabelInfo.f)).append(signLabelInfo.br)
.append(getFormatLabel("交班小票", signLabelInfo.l,signLabelInfo.center)).append(signLabelInfo.br)
.append("交班时间: ").append(DateUtil.format(handoverRecord.getHandoverTime(), "yyyy-MM-dd HH:mm:ss")).append(signLabelInfo.br)
.append("收银员: ").append(handoverRecord.getStaffName()).append(signLabelInfo.br)
.append("当班总收入: ").append(handoverRecord.getHandAmount()).append(signLabelInfo.br)
.append("现金收入: ").append(handoverRecord.getCashAmount()).append(signLabelInfo.br)
.append("微信收入: ").append(handoverRecord.getWechatAmount()).append(signLabelInfo.br)
.append("支付宝收入: ").append(handoverRecord.getAlipayAmount()).append(signLabelInfo.br)
.append("会员支付: ").append(handoverRecord.getVipPay()).append(signLabelInfo.br)
.append("会员充值: ").append(handoverRecord.getVipRecharge()).append(signLabelInfo.br)
.append(getFormatLabel(handoverRecord.getShopName(), signLabelInfo.center, signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel("交班小票", signLabelInfo.s, signLabelInfo.center)).append(signLabelInfo.br)
.append(getFormatLabel("交班时间: " + DateUtil.format(handoverRecord.getHandoverTime(), "yyyy/MM/dd HH:mm:ss"), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel("收银员: " + handoverRecord.getStaffName(), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel("交班周期: " + DateUtil.format(handoverRecord.getLoginTime(), "dd日HH:mm") + " - " +
DateUtil.format(handoverRecord.getHandoverTime(), "dd日HH:mm"), signLabelInfo.s)).append(signLabelInfo.br)
.append(signLabelInfo.br)
.append(signLabelInfo.br)
.append("分类数据").append(signLabelInfo.br).append(signLabelInfo.br)
.append(getFormatLabel("名称 数量 总计 ", signLabelInfo.s))
.append(signLabelInfo.br)
.append(getFormatLabel("当班营业总额: " + handoverRecord.getHandAmount(), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel("实际收款的支付方式", signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel(leftRightAlign(" 现金:", handoverRecord.getCashAmount().toPlainString(), 32), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel(leftRightAlign(" 微信:", handoverRecord.getWechatAmount().toPlainString(), 32), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel(leftRightAlign(" 支付宝:", handoverRecord.getAlipayAmount().toPlainString(), 32), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel(leftRightAlign(" 二维码收款:", "", 32), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel(leftRightAlign(" 扫码收款:", "", 32), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel(leftRightAlign(" 充值:", handoverRecord.getVipRecharge().toPlainString(), 32), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel("非实际收款的支付方式", signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel(leftRightAlign(" 挂账:", handoverRecord.getCreditAmount().toPlainString(), 32), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel(leftRightAlign(" 余额:", handoverRecord.getVipPay().toPlainString(), 32), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel("--------------------------------", signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel("退菜/退款", signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel(leftRightAlign(" 退款金额:", handoverRecord.getRefundAmount().toPlainString(), 32), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel(leftRightAlign(" 退菜数量:", "", 32), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel("--------------------------------", signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel(leftRightAlign("订单(数量/订单总额)", handoverRecord.getOrderCount() + "/" + handoverRecord.getHandAmount(), 32), signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel("----------- 销售数据 -----------", signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel(formatItemLine("商品分类", "数量", "总计", 14, 8), signLabelInfo.s))
.append(signLabelInfo.br);
if (StrUtil.isNotBlank(handoverRecord.getCategoryData())) {
@@ -180,49 +216,18 @@ public interface PrinterImpl {
String categoryName = info.getString("categoryName");
Integer quantity = info.getInteger("quantity");
BigDecimal amount = info.getBigDecimal("amount");
builder.append(getRow(categoryName, "", quantity.toString(), amount.toPlainString(), 20, 0, 6, 6)).append(signLabelInfo.br);
builder.append(getFormatLabel(formatItemLine(categoryName, quantity.toString(), amount.toPlainString(), 14, 8), signLabelInfo.s)).append(signLabelInfo.br);
});
}
builder.append(signLabelInfo.br);
builder.append(signLabelInfo.br);
builder.append("商品数据")
.append(signLabelInfo.br)
.append(signLabelInfo.br);
builder.append(getFormatLabel("名称 总计 ", signLabelInfo.s))
.append(signLabelInfo.br)
.append(signLabelInfo.br);
if (StrUtil.isNotBlank(handoverRecord.getProductData())) {
JSONArray.parseArray(handoverRecord.getProductData()).forEach(item -> {
JSONObject info = (JSONObject) item;
String productName = info.getString("productName");
String skuName = info.getString("skuName");
if (StrUtil.isNotBlank(skuName)) {
productName = productName + "-" + skuName;
}
BigDecimal num = info.getBigDecimal("num");
// builder.append(signLabelInfo.getRs(5));
builder.append(getRow(productName, "", "", num.toPlainString(), 25, 0, 1, 6)).append(signLabelInfo.br);
});
}
builder
.append(signLabelInfo.br)
.append(signLabelInfo.br)
.append("快捷收款金额: ").append(handoverRecord.getQuickInAmount()).append(signLabelInfo.br)
.append("退款金额: ").append(handoverRecord.getRefundAmount()).append(signLabelInfo.br)
.append("总收入: ").append(handoverRecord.getHandAmount()).append(signLabelInfo.br)
.append("挂账金额: ").append(handoverRecord.getCreditAmount()).append(signLabelInfo.br)
.append("总订单数: ").append(handoverRecord.getOrderCount()).append(signLabelInfo.br)
.append("打印时间: ").append(DateUtil.date()).append(signLabelInfo.br)
builder.append(getFormatLabel("退菜/退款", signLabelInfo.s)).append(signLabelInfo.br)
.append(getFormatLabel("打印时间: " + DateUtil.format(DateUtil.date(), "yyyy/MM/dd HH:mm:ss"), signLabelInfo.s)).append(signLabelInfo.br)
.append(signLabelInfo.getOut(180))
.append(signLabelInfo.cut)
;
.append(signLabelInfo.cut);
return builder.toString();
}
/**
* 构建订单打印元数据
* 构建结算单 预结算单订单打印元数据
*
* @param printInfoDTO 打印信息
* @param detailList 订单详情
@@ -231,51 +236,29 @@ public interface PrinterImpl {
default String buildOrderPrintData(PrinterHandler.PrintInfoDTO printInfoDTO, List<OrderDetail> detailList) {
PrintSignLabel signLabelInfo = getSignLabelInfo();
StringBuilder data = new StringBuilder();
data.append(getFormatLabel(printInfoDTO.getShopName(), signLabelInfo.center, signLabelInfo.f)).append(signLabelInfo.br);
// data.append(StrUtil.format("<C><F>{}</F></C><BR>", printInfoDTO.getShopName()));
// data.append("<BR>");
// data.append("<OUT:30>");
data.append(getFormatLabel(StrUtil.format("{} #{}", printInfoDTO.getPrintTitle(), printInfoDTO.getCount()), signLabelInfo.l, signLabelInfo.center))
.append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("桌号: {}", printInfoDTO.getPickupNum()), signLabelInfo.l, signLabelInfo.center))
.append(signLabelInfo.br);
data.append(getFormatLabel(printInfoDTO.getShopName(), signLabelInfo.s, signLabelInfo.center)).append(signLabelInfo.br);
data.append(getFormatLabel(printInfoDTO.getPrintTitle(), signLabelInfo.s, signLabelInfo.center)).append(signLabelInfo.br);
data.append(getFormatLabel(printInfoDTO.getPickupNum(), signLabelInfo.f)).append(signLabelInfo.br);
data.append(getFormatLabel(getFormatLabel(leftRightAlign(printInfoDTO.getPrintType(), StrUtil.isNotBlank(printInfoDTO.getSeatNum()) ? printInfoDTO.getSeatNum() + "" : "", 32))
, signLabelInfo.s)).append(signLabelInfo.br);
if (StrUtil.isNotBlank(printInfoDTO.getTradeDate())) {
data.append(getFormatLabel(StrUtil.format("结账时间:{}", printInfoDTO.getTradeDate()), signLabelInfo.s)).append(signLabelInfo.br);
}
data.append(getFormatLabel("--------------------------------", signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel(formatItemLine("品名", "单价", "数量", 18, 9), signLabelInfo.s)).append(signLabelInfo.br);
// data.append(StrUtil.format("<C><BOLD>{}【{}】</BOLD></C><BR>", printInfoDTO.getPrintTitle(), printInfoDTO.getPickupNum()));
//if (Objects.nonNull(printInfoDTO.getOutNumber())) {
// data.append(StrUtil.format("<CB><BOLD>{}</BOLD></CB>",printInfoDTO.getOutNumber()));
//}
// data.append("<OUT:30>");
// data.append("<BR>");
data.append(getFormatLabel(StrUtil.format("订单号:{}", printInfoDTO.getOrderNo()), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>订单号:{}</S><BR>", printInfoDTO.getOrderNo()));
data.append(getFormatLabel(StrUtil.format("交易时间:{}", printInfoDTO.getTradeDate()), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>交易时间:{}</S><BR>", printInfoDTO.getTradeDate()));
data.append(getFormatLabel(StrUtil.format("收银员:{}", printInfoDTO.getOperator()), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>收银员:{}</S><BR>", printInfoDTO.getOperator()));
data.append(signLabelInfo.br);
data.append(signLabelInfo.br);
// data.append("<OUT:15>");
// data.append("<BR>");
// 18个空格 12
data.append(getFormatLabel("品名 数量 单价 ", signLabelInfo.s))
.append(signLabelInfo.br);
// data.append("<S>品名 数量 小计</S><BR>");
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
.append(signLabelInfo.br);
// data.append("<S>--------------------------------</S><BR>");
for (OrderDetail detail : detailList) {
String number = detail.getNum().stripTrailingZeros().toPlainString();
String row = getRow(detail.getProductName(), "", StrUtil.format("{}{}", number, detail.getReturnNum().compareTo(BigDecimal.ZERO) > 0 ?
"(退" + detail.getReturnNum().stripTrailingZeros().toPlainString() + ")" : ""),
toPlainStr(detail.getUnitPrice().stripTrailingZeros().toPlainString()), 21, 0, 5, 6);
data.append(row);
BigDecimal subtract = detail.getNum().subtract(detail.getReturnNum());
if (subtract.compareTo(BigDecimal.ZERO) <= 0) {
continue;
}
String number = subtract.stripTrailingZeros().toPlainString();
String unitPrice = toPlainStr(detail.getUnitPrice().stripTrailingZeros().toPlainString());
data.append(getFormatLabel(formatItemLine(detail.getProductName(), unitPrice, number, 18, 7), signLabelInfo.s)).append(signLabelInfo.br);
if (StrUtil.isNotBlank(detail.getSkuName())) {
data.append(getFormatLabel(StrUtil.format("规格:{}", detail.getSkuName()), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append("<S>规格:").append(detail.getSkuName()).append("</S><BR>");
}
String proGroupInfo = detail.getProGroupInfo();
if (StrUtil.isBlank(proGroupInfo)) {
@@ -290,84 +273,191 @@ public interface PrinterImpl {
jsonObject.getJSONArray("goods").forEach(item -> {
String proName = ((JSONObject) item).getString("proName");
String qty = ((JSONObject) item).getString("number");
String subRow = getRow(" - " + proName, "", qty, "0.00", 21, 0, 5, 6);
data.append(subRow);
data.append(getFormatLabel(formatItemLine(" - " + proName, "", qty, 18, 9), signLabelInfo.s)).append(signLabelInfo.br);
});
}
}
if(StrUtil.isNotBlank(printInfoDTO.getSeatAmount())){
String row = getRow("餐位费", "", StrUtil.format("{}{}", printInfoDTO.getSeatNum(),""),
toPlainStr(printInfoDTO.getSeatAmount()), 21, 0, 5, 6);
data.append(row);
if (StrUtil.isNotBlank(printInfoDTO.getSeatAmount())) {
data.append(getFormatLabel(formatItemLine("餐位费", printInfoDTO.getSeatAmount(), printInfoDTO.getSeatNum(), 18, 9), signLabelInfo.s)).append(signLabelInfo.br);
}
if(StrUtil.isNotBlank(printInfoDTO.getPackFee())){
String row = getRow("打包费", "", "",
toPlainStr(printInfoDTO.getPackFee()), 21, 0, 5, 6);
data.append(row);
if (StrUtil.isNotBlank(printInfoDTO.getPackFee())) {
data.append(getFormatLabel(formatItemLine("打包费", toPlainStr(printInfoDTO.getPackFee()), "", 18, 9), signLabelInfo.s)).append(signLabelInfo.br);
}
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
.append(signLabelInfo.br);
data.append(getFormatLabel(leftRightAlign("原价:", printInfoDTO.getOriginalAmount(), 32), signLabelInfo.s)).append(signLabelInfo.br);
if (ObjectUtil.isNotNull(printInfoDTO.getDiscountAmount())) {
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
.append(signLabelInfo.br);
// data.append("<S>--------------------------------</S><BR>");
data.append(getFormatLabel(StrUtil.format("原价:{}", toPlainStr(printInfoDTO.getOriginalAmount())), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>原价:{}</S><BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
data.append(getFormatLabel(StrUtil.format("优惠:-{}", toPlainStr(printInfoDTO.getDiscountAmount())), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>折扣:-{}</S><BR>", toPlainStr(printInfoDTO.getDiscountAmount())));
data.append(getFormatLabel(leftRightAlign("优惠:", "-" + printInfoDTO.getDiscountAmount(), 32), signLabelInfo.s)).append(signLabelInfo.br);
}
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
.append(signLabelInfo.br);
// data.append("<S>--------------------------------</S><BR>");
String t = "" + printInfoDTO.getPayAmount();
if (printInfoDTO.isReturn()) {
data.append(getFormatLabel(StrUtil.format("应退:{}", t), signLabelInfo.f))
.append(signLabelInfo.br);
// data.append("<F>应退").append(t).append("</F><BR>");
} else {
data.append(getFormatLabel(StrUtil.format("应收:{}", t), signLabelInfo.f))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<F>应收:{}</F><BR>", t));
if (StrUtil.isNotBlank(printInfoDTO.getRemark())) {
data.append(getFormatLabel(StrUtil.format("备注:{}", printInfoDTO.getRemark()), signLabelInfo.s)).append(signLabelInfo.br);
}
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
.append(signLabelInfo.br);
// data.append("<S>--------------------------------</S><BR>");
if (ObjectUtil.isNotEmpty(printInfoDTO.getPayType()) && ObjectUtil.isNotNull(printInfoDTO.getPayType()) && "deposit".equals(printInfoDTO.getPayType())) {
data.append(getFormatLabel(StrUtil.format("储值:{}", toPlainStr(printInfoDTO.getOriginalAmount())), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>储值:{}</S><BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
data.append(getFormatLabel(StrUtil.format("积分:{}", printInfoDTO.getIntegral()), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>积分:{}</S><BR>", printInfoDTO.getIntegral()));
data.append(getFormatLabel(StrUtil.format("余额:{}", toPlainStr(printInfoDTO.getBalance())), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>余额:{}</S><BR>", toPlainStr(printInfoDTO.getBalance())));
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
.append(signLabelInfo.br);
data.append(getFormatLabel("--------------------------------", signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel(leftRightAlign("应付:", printInfoDTO.getPayAmount(), 16), signLabelInfo.f)).append(signLabelInfo.br);
if ("结算单".equals(printInfoDTO.getPrintTitle())) {
data.append(getFormatLabel("--------------------------------", signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel(leftRightAlign("已付:", printInfoDTO.getPayAmount(), 16), signLabelInfo.f)).append(signLabelInfo.br);
data.append(getFormatLabel(leftRightAlign("支付方式:", printInfoDTO.getPayType(), 32), signLabelInfo.s)).append(signLabelInfo.br);
}
// data.append("<S>--------------------------------</S><BR>");
if (StrUtil.isNotBlank(printInfoDTO.getRemark())) {
data.append(getFormatLabel(StrUtil.format("备注{}", printInfoDTO.getRemark()), signLabelInfo.l, signLabelInfo.bold))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<L><BOLD>备注:{}</BOLD></L><BR>", printInfoDTO.getRemark()));
}
// if (Objects.nonNull(printInfoDTO.getOutNumber())) {
// data.append(getFormatLabel(printInfoDTO.getOutNumber(), signLabelInfo.center, signLabelInfo.qr))
// .append(signLabelInfo.br);
//// data.append("<QR>".concat(printInfoDTO.getOutNumber()).concat("</QR><BR>"));
// }
data.append(getFormatLabel(StrUtil.format("打印时间:{}", DateUtil.date().toString()), signLabelInfo.s))
.append(signLabelInfo.br)
.append(signLabelInfo.br);
// data.append("<S>打印时间:").append(DateUtil.date().toDateStr()).append("</S><BR>");
// data.append("<OUT:180>");
data.append(getFormatLabel("--------------------------------", signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("操作员:{}", printInfoDTO.getOperator()), signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("打印时间{}", DateUtil.date().toString()), signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("订单号:{}", printInfoDTO.getOrderNo()), signLabelInfo.s)).append(signLabelInfo.br);
data.append(signLabelInfo.getOut(180));
data.append(signLabelInfo.cut);
// data.append("<PCUT>");
return data.toString();
}
/**
* 构建客看单订单打印元数据
*
* @param printInfoDTO 打印信息
* @param detailList 订单详情
* @return 订单打印元数据
*/
default String buildGuestOrderPrintData(PrinterHandler.PrintInfoDTO printInfoDTO, List<OrderDetail> detailList) {
PrintSignLabel signLabelInfo = getSignLabelInfo();
StringBuilder data = new StringBuilder();
data.append(getFormatLabel(printInfoDTO.getShopName(), signLabelInfo.s, signLabelInfo.center)).append(signLabelInfo.br);
data.append(getFormatLabel("客看单", signLabelInfo.s, signLabelInfo.center)).append(signLabelInfo.br);
if (StrUtil.isNotBlank(printInfoDTO.getPickupNum())) {
data.append(getFormatLabel(printInfoDTO.getPickupNum(), signLabelInfo.f)).append(signLabelInfo.br);
}
data.append(getFormatLabel(getFormatLabel(leftRightAlign(printInfoDTO.getPrintType(), StrUtil.isNotBlank(printInfoDTO.getSeatNum()) ? printInfoDTO.getSeatNum() + "" : "", 32))
, signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel("--------------------------------", signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel(formatItemLine("品名", "单价", "数量", 18, 9), signLabelInfo.s)).append(signLabelInfo.br);
for (OrderDetail detail : detailList) {
BigDecimal subtract = detail.getNum().subtract(detail.getReturnNum());
if (subtract.compareTo(BigDecimal.ZERO) <= 0) {
continue;
}
String number = subtract.stripTrailingZeros().toPlainString();
String unitPrice = toPlainStr(detail.getUnitPrice().stripTrailingZeros().toPlainString());
data.append(getFormatLabel(formatItemLine(detail.getProductName(), unitPrice, number, 18, 7), signLabelInfo.s)).append(signLabelInfo.br);
if (StrUtil.isNotBlank(detail.getSkuName())) {
data.append(getFormatLabel(StrUtil.format("规格:{}", detail.getSkuName()), signLabelInfo.s))
.append(signLabelInfo.br);
}
String proGroupInfo = detail.getProGroupInfo();
if (StrUtil.isBlank(proGroupInfo)) {
continue;
}
if (!JSONUtil.isTypeJSONArray(proGroupInfo)) {
continue;
}
JSONArray subItems = com.alibaba.fastjson2.JSONArray.parseArray(proGroupInfo);
for (Object subItem : subItems) {
JSONObject jsonObject = (JSONObject) subItem;
jsonObject.getJSONArray("goods").forEach(item -> {
String proName = ((JSONObject) item).getString("proName");
String qty = ((JSONObject) item).getString("number");
data.append(getFormatLabel(formatItemLine(" - " + proName, "", qty, 18, 9), signLabelInfo.s)).append(signLabelInfo.br);
});
}
}
if (StrUtil.isNotBlank(printInfoDTO.getSeatAmount())) {
data.append(getFormatLabel(formatItemLine("餐位费", printInfoDTO.getSeatAmount(), printInfoDTO.getSeatNum(), 18, 9), signLabelInfo.s)).append(signLabelInfo.br);
}
if (StrUtil.isNotBlank(printInfoDTO.getPackFee())) {
data.append(getFormatLabel(formatItemLine("打包费", toPlainStr(printInfoDTO.getPackFee()), "", 18, 9), signLabelInfo.s)).append(signLabelInfo.br);
}
data.append(getFormatLabel("-------------------------------", signLabelInfo.s))
.append(signLabelInfo.br);
data.append(getFormatLabel(leftRightAlign("原价:", printInfoDTO.getOriginalAmount(), 32), signLabelInfo.s)).append(signLabelInfo.br);
if (ObjectUtil.isNotNull(printInfoDTO.getDiscountAmount())) {
data.append(getFormatLabel(leftRightAlign("优惠:", "-" + printInfoDTO.getDiscountAmount(), 32), signLabelInfo.s)).append(signLabelInfo.br);
}
if (StrUtil.isNotBlank(printInfoDTO.getRemark())) {
data.append(getFormatLabel(StrUtil.format("备注:{}", printInfoDTO.getRemark()), signLabelInfo.s)).append(signLabelInfo.br);
}
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
.append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("操作员:{}", printInfoDTO.getOperator()), signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("打印时间:{}", DateUtil.date().toString()), signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("订单号:{}", printInfoDTO.getOrderNo()), signLabelInfo.s)).append(signLabelInfo.br);
data.append(signLabelInfo.getOut(180));
data.append(signLabelInfo.cut);
return data.toString();
}
/**
* 构建退款订单打印元数据
*
* @param printInfoDTO 打印信息
* @param detailList 订单详情
* @return 订单打印元数据
*/
default String buildRefundOrderPrintData(PrinterHandler.PrintInfoDTO printInfoDTO, List<OrderDetail> detailList) {
PrintSignLabel signLabelInfo = getSignLabelInfo();
StringBuilder data = new StringBuilder();
data.append(getFormatLabel(printInfoDTO.getShopName(), signLabelInfo.s, signLabelInfo.center)).append(signLabelInfo.br);
data.append(getFormatLabel(printInfoDTO.getPrintTitle(), signLabelInfo.s, signLabelInfo.center)).append(signLabelInfo.br);
data.append(getFormatLabel(printInfoDTO.getPickupNum(), signLabelInfo.f)).append(signLabelInfo.br);
data.append(getFormatLabel(getFormatLabel(leftRightAlign(printInfoDTO.getPrintType(), StrUtil.isNotBlank(printInfoDTO.getSeatNum()) ? printInfoDTO.getSeatNum() + "" : "", 32))
, signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel("--------------------------------", signLabelInfo.s)).append(signLabelInfo.br);
if (CollUtil.isNotEmpty(detailList)) {
data.append(getFormatLabel(formatItemLine("退款明细", "数量", "小计", 18, 9), signLabelInfo.s)).append(signLabelInfo.br);
for (OrderDetail detail : detailList) {
String number = detail.getNum().stripTrailingZeros().toPlainString();
String amount = "";
if ("退款单".equals(printInfoDTO.getPrintTitle())) {
amount = detail.getReturnAmount().stripTrailingZeros().toPlainString();
}
data.append(getFormatLabel(formatItemLine(detail.getProductName(), number, amount, 18, 7), signLabelInfo.s)).append(signLabelInfo.br);
if (StrUtil.isNotBlank(detail.getSkuName())) {
data.append(getFormatLabel(StrUtil.format("规格:{}", detail.getSkuName()), signLabelInfo.s))
.append(signLabelInfo.br);
}
String proGroupInfo = detail.getProGroupInfo();
if (StrUtil.isBlank(proGroupInfo)) {
continue;
}
if (!JSONUtil.isTypeJSONArray(proGroupInfo)) {
continue;
}
JSONArray subItems = com.alibaba.fastjson2.JSONArray.parseArray(proGroupInfo);
for (Object subItem : subItems) {
JSONObject jsonObject = (JSONObject) subItem;
jsonObject.getJSONArray("goods").forEach(item -> {
String proName = ((JSONObject) item).getString("proName");
String qty = ((JSONObject) item).getString("number");
data.append(getFormatLabel(formatItemLine(" - " + proName, "", qty, 18, 9), signLabelInfo.s)).append(signLabelInfo.br);
});
}
}
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
.append(signLabelInfo.br);
}
if ("退款单".equals(printInfoDTO.getPrintTitle())) {
data.append(getFormatLabel(leftRightAlign("退款总计", printInfoDTO.getRefundAmount(), 16), signLabelInfo.f)).append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("退款方式: {}", printInfoDTO.getRefundType()), signLabelInfo.s))
.append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("退款原因: {}", printInfoDTO.getRefundReason()), signLabelInfo.s))
.append(signLabelInfo.br);
} else {
data.append(getFormatLabel(StrUtil.format("退菜原因: {}", printInfoDTO.getRefundReason()), signLabelInfo.s))
.append(signLabelInfo.br);
}
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
.append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("操作员:{}", printInfoDTO.getOperator()), signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("打印时间:{}", DateUtil.date().toString()), signLabelInfo.s)).append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("订单号:{}", printInfoDTO.getOrderNo()), signLabelInfo.s)).append(signLabelInfo.br);
data.append(signLabelInfo.getOut(180));
data.append(signLabelInfo.cut);
return data.toString();
}
/**
* 构建菜品单打印数据
*
@@ -491,9 +581,9 @@ public interface PrinterImpl {
getFormatLabel(shopNote, signLabelInfo.s) +
signLabelInfo.br +
"--------------------------------" + signLabelInfo.br +
getFormatLabel(StrUtil.format("取号时间{}", DateUtil.format(takeTime, "yyyy-MM-dd HH:mm:ss")), signLabelInfo.s) +
getFormatLabel(StrUtil.format("取号时间: {}", DateUtil.format(takeTime, "yyyy-MM-dd HH:mm:ss")), signLabelInfo.s) +
signLabelInfo.br +
getFormatLabel(StrUtil.format("打印时间{}", DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss")), signLabelInfo.s) +
getFormatLabel(StrUtil.format("打印时间: {}", DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss")), signLabelInfo.s) +
signLabelInfo.br +
signLabelInfo.cut;
}
@@ -596,6 +686,97 @@ public interface PrinterImpl {
if (StrUtil.isBlank(str)) {
return "0";
}
return NumberUtil.roundDown(new BigDecimal(str), 2).toPlainString();
return NumberUtil.round(new BigDecimal(str), 2).toPlainString();
}
// 两个内容 左 右对齐
default String leftRightAlign(String leftText, String rightText, int totalWidth) {
if (leftText == null) leftText = "";
if (rightText == null) rightText = "";
// 1. 计算真实打印宽度(汉字=2英文=1
int leftWidth = getStringWidth(leftText);
int rightWidth = getStringWidth(rightText);
// 总长度 - 右边长度 = 左边可用长度
// 2. 计算中间需要填充的空格数
int spaceNum = totalWidth - leftWidth - rightWidth;
if (spaceNum < 0) spaceNum = 0; // 防止负数
// 3. 生成空格
String spaces = " ".repeat(spaceNum);
// 4. 三段式拼接:左边 + 空格 + 右边
return leftText + spaces + rightText;
}
/**
* 获取字符串实际打印宽度(汉字=2字母/数字=1
*/
static int getStringWidth(String str) {
if (str == null || str.isEmpty()) return 0;
int width = 0;
for (char c : str.toCharArray()) {
if (String.valueOf(c).getBytes().length > 1) {
width += 2; // 中文
} else {
width += 1; // 英文/数字
}
}
return width;
}
/**
* 通用三列对齐方法(严格总长度)
* 规则key1=左对齐key2=左对齐key3=右对齐
* 整行总长度 = totalWidth绝不超界
*/
default String formatItemLine(String key1, String key2, String key3,
int key1Width,
int key2Width) {
// 1. 空值安全处理
key1 = Objects.toString(key1, "");
key2 = Objects.toString(key2, "");
key3 = Objects.toString(key3, "");
// 👉 核心key1 超长截取 + 加 ...
key1 = truncateWithEllipsis(key1, key1Width);
int w1 = getStringWidth(key1);
int w2 = getStringWidth(key2);
int w3 = getStringWidth(key3);
int space1 = Math.max(key1Width - w1, 0);
int space2 = Math.max(key2Width - w2, 0);
// 6. 最终按总显示宽度截断100%不超界)
int usedWidth = key1Width + key2Width + w3;
int space3 = Math.max(32 - usedWidth, 0);
// 5. 拼接左1 + 空格 + 左2 + 空格 + (靠右空格) + 右3
return key1 + " ".repeat(space1)
+ key2 + " ".repeat(space2)
+ " ".repeat(space3)
+ key3;
}
private String truncateWithEllipsis(String text, int maxWidth) {
if (maxWidth <= 0) return "";
if (getStringWidth(text) <= maxWidth) {
return text;
}
StringBuilder sb = new StringBuilder();
int currentWidth = 0;
int ellipsisWidth = getStringWidth("...");
for (char c : text.toCharArray()) {
int charWidth = (c > 127) ? 2 : 1;
// 剩下的宽度必须能放下 当前字符 + ...
if (currentWidth + charWidth + ellipsisWidth > maxWidth) {
break;
}
sb.append(c);
currentWidth += charWidth;
}
return sb + "..";
}
}

View File

@@ -28,6 +28,7 @@ import java.util.*;
/**
* 博实结-云享印打印机
* 接口文档 <a href="https://bsj2.yuque.com/bsj/izhmfn/rr8b5g?#ZbE6s">
*
* @author Administrator
*/
@Slf4j
@@ -58,6 +59,7 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
.setCenter(new String[]{"<C>", "</C>"})
.setCenterBold(new String[]{"<CB>", "</CB>"})
.setRs("RS")
.setBr("<BR>")
.setBold(new String[]{"<B>", "</B>"});
@Override
@@ -103,18 +105,20 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
}
@Override
protected void normalDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
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\":\"您有一笔新的订单,请及时处理\"}";
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(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
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\":\"\"}";
@@ -124,92 +128,36 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
}
@Override
protected void returnOrderPrint(OrderInfo orderInfo, PrintMachine machine, String balance, List<OrderDetail> detailList) {
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
PrintInfoDTO printInfoDTO = new PrintInfoDTO().setShopName(shopInfo.getShopName()).setPrintType("普通打印").setPickupNum(getPickupNum(orderInfo))
.setOrderNo(orderInfo.getOrderNo()).setTradeDate(DateUtil.format(orderInfo.getCreateTime(), "yyyy-MM-dd HH:mm:ss"))
.setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
.setOriginalAmount(orderInfo.getOriginAmount().toPlainString()).setReturn(isReturn(orderInfo))
.setBalance(balance).setPayType((ObjectUtil.isEmpty(orderInfo.getPayType()) || ObjectUtil.isNull(orderInfo.getPayType()) ? "" : orderInfo.getPayType())).setIntegral("0")
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle("退款单")
.setRemark(orderInfo.getRemark())
// 使用累计的总优惠金额null 表示没有优惠
.setDiscountAmount(orderInfo.getDiscountAllAmount() != null
? orderInfo.getDiscountAllAmount().toPlainString()
: "0.00");
String data = buildOrderPrintData(printInfoDTO, detailList);
String voiceJson = "{\"PbizType\":\"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(orderInfo.getId(), machine, "退款单", data, resp);
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
protected void normalOrderPrint(OrderInfo orderInfo, boolean isPre, PrintMachine machine, String balance, List<OrderDetail> detailList) {
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
long count = orderInfoService.count(new QueryWrapper().eq(OrderInfo::getTradeDay, orderInfo.getTradeDay())
.eq(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode())
.eq(OrderInfo::getShopId, orderInfo.getShopId())
.le(OrderInfo::getCreateTime, orderInfo.getCreateTime()));
PrintInfoDTO printInfoDTO = new PrintInfoDTO().setShopName(shopInfo.getShopName())
.setPrintType("普通打印").setPickupNum(getPickupNum(orderInfo))
.setOrderNo(orderInfo.getOrderNo()).setTradeDate(DateUtil.format(orderInfo.getCreateTime(), "yyyy-MM-dd HH:mm:ss"))
.setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
.setReturn(isReturn(orderInfo))
.setBalance(balance).setPayType((ObjectUtil.isEmpty(orderInfo.getPayType()) || ObjectUtil.isNull(orderInfo.getPayType()) ? "" : orderInfo.getPayType())).setIntegral("0")
.setOutNumber(orderInfo.getTakeCode())
.setPrintTitle(isPre ? "预结算单" : "结算单")
.setCount(count)
.setRemark(orderInfo.getRemark())
// 使用累计的总优惠金额null 表示没有优惠
.setDiscountAmount(orderInfo.getDiscountAllAmount() != null
? orderInfo.getDiscountAllAmount().toPlainString()
: "0.00");
BigDecimal originalAmount = orderInfo.getOriginAmount()==null?BigDecimal.ZERO:orderInfo.getOriginAmount();
printInfoDTO.setOriginalAmount(originalAmount.toPlainString());
if (isPre) {
originalAmount = BigDecimal.ZERO;
for (OrderDetail orderDetail : detailList) {
if(orderDetail.getIsGift()==1){
continue;
}else if(orderDetail.getDiscountSaleAmount().compareTo(BigDecimal.ZERO) > 0){
originalAmount = originalAmount.add((orderDetail.getNum().subtract(orderDetail.getReturnNum()).subtract(orderDetail.getRefundNum())).multiply(orderDetail.getUnitPrice()));
}else {
originalAmount = originalAmount.add((orderDetail.getNum().subtract(orderDetail.getReturnNum()).subtract(orderDetail.getRefundNum())).multiply(orderDetail.getPrice()));
}
}
printInfoDTO.setOriginalAmount((originalAmount.add(orderInfo.getSeatAmount()).add(orderInfo.getPackFee())).toPlainString());
printInfoDTO.setPayAmount(originalAmount.add(orderInfo.getSeatAmount()).add(orderInfo.getPackFee())
.subtract(orderInfo.getDiscountAllAmount()).setScale(2, RoundingMode.HALF_UP).toPlainString());
}else {
printInfoDTO.setPayAmount(originalAmount.subtract(orderInfo.getDiscountAllAmount()).setScale(2, RoundingMode.HALF_UP).toPlainString());
}
printInfoDTO.setPrintTitle(printInfoDTO.getPrintTitle());
if (orderInfo.getSeatNum() != null && orderInfo.getSeatAmount().compareTo(BigDecimal.ZERO) > 0) {
printInfoDTO.setSeatNum(orderInfo.getSeatNum().toString());
printInfoDTO.setSeatAmount(orderInfo.getSeatAmount().divide(BigDecimal.valueOf(orderInfo.getSeatNum()), 2, RoundingMode.DOWN).toPlainString());
}
if (orderInfo.getPackFee().compareTo(BigDecimal.ZERO) > 0) {
printInfoDTO.setPackFee(orderInfo.getPackFee().toPlainString());
}
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;
}
String voiceJson = "{\"PbizType\":\"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(orderInfo.getId(), machine, "结算单", data, resp);
@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;
}
/**
@@ -241,7 +189,6 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
*/
private static String getToken(String timestamp, String requestId) {
StringBuilder token = new StringBuilder();
// StringBuilder encode = new StringBuilder();
SortedMap<String, Object> map = new TreeMap<>();
map.put("appId", APP_ID);
map.put("timestamp", timestamp);
@@ -251,15 +198,23 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
String key = next.getKey();
Object value = next.getValue();
token.append(key).append(value);
// encode.append(key).append("=").append(value).append("&");
}
// Map<String, String> finalMap = new HashMap<>();
// finalMap.put("ENCODE", encode.toString());
// finalMap.put("TOKEN", SecureUtil.md5(token + APP_SECRET).toUpperCase());
// return finalMap;
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);
}
/**
* 检查打印状态
@@ -284,14 +239,4 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
log.info("云想印打印机:{},任务:{}状态:{}", devName, taskId, s);
return s;
}
/**
* 计算优惠金额:优先使用 discountAllAmount如果为 null 则返回 0
*/
private String calculateDiscountAmount(OrderInfo orderInfo) {
return orderInfo.getDiscountAllAmount() != null
? orderInfo.getDiscountAllAmount().toPlainString()
: "0.00";
}
}

View File

@@ -314,7 +314,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
}
orderDetails.forEach(item -> item.setOrderTime(DateUtil.date().toLocalDateTime()));
AssertUtil.isListEmpty(orderDetails, "下单失败 购物车为空");
processOrderDetails(orderDetails, param.getLimitRate(),param);
processOrderDetails(orderDetails, param.getLimitRate(), param);
//生成订单
OrderInfo orderInfo = initOrderInfo(param, shopInfo, table);
orderDetailService.createOrderDetails(orderInfo.getId(), orderDetails);
@@ -324,6 +324,9 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
.eq(CashierCart::getTableCode, param.getTableCode())
);
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完成
//orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_0"
@@ -359,6 +362,9 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
throw new OrderCancelException("订单已过期,请重新下单");
}
}
if (StrUtil.isNotBlank(param.getDineMode())) {
orderInfo.setDineMode(param.getDineMode());
}
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
AssertUtil.isNull(shopInfo, "生成订单失败,店铺信息不存在");
if (param.isVipPrice() && !shopInfo.getIsMemberPrice().equals(1)) {
@@ -539,7 +545,9 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
throw new OrderValidateException("生成支付订单失败,支付金额不正确");
}
orderInfo.setPackFee(packAmount.getPrice());
orderInfo.setRemark(param.getRemark());
if (StrUtil.isNotBlank(param.getRemark())) {
orderInfo.setRemark(param.getRemark());
}
//生成订单 //discount_info 所有折扣 几折 折扣金额 满减金额 优惠券金额 积分抵扣金额 抹零
upOrderPayInfo(orderInfo, param);
@@ -554,7 +562,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
if (param.getTargetOrderId() == null && StrUtil.isBlank(param.getTargetTableCode())) {
throw new CzgException("转台失败,请选择目标台桌后转台");
}
if(param.getAllMerge()==null){
if (param.getAllMerge() == null) {
param.setAllMerge(0);
}
OrderInfo sourceOrder = orderInfoService.getById(param.getSourceOrderId());
@@ -569,13 +577,13 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
ShopTable shopTable = shopTableService.getOneByTableCode(sourceOrder.getShopId(), param.getTargetTableCode());
sourceOrder.setTableCode(shopTable.getTableCode());
sourceOrder.setTableName(shopTable.getName());
if(param.getAllMerge()==1){
if (param.getAllMerge() == 1) {
OrderInfo upOrder = new OrderInfo();
upOrder.setTableCode(shopTable.getTableCode());
upOrder.setTableName(shopTable.getName());
orderInfoService.update(upOrder, new QueryWrapper().eq(OrderInfo::getId, sourceOrder.getId()));
targetOrder=sourceOrder;
}else {
targetOrder = sourceOrder;
} else {
OrderInfoAddDTO addDTO = new OrderInfoAddDTO();
addDTO.setShopId(sourceOrder.getShopId());
addDTO.setStaffId(sourceOrder.getStaffId());
@@ -615,16 +623,16 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
if (count < 1) {
throw new CzgException("转台失败,该订单无可转商品");
}
orderDetailService.update(orderDetailUp,new QueryWrapper().eq(OrderDetail::getOrderId, sourceOrder.getId()));
orderDetailService.update(orderDetailUp, new QueryWrapper().eq(OrderDetail::getOrderId, sourceOrder.getId()));
} else {
orderDetailService.update(orderDetailUp,
new QueryWrapper().eq(OrderDetail::getOrderId, sourceOrder.getId()).in(OrderDetail::getId, param.getDetailIds()));
}
if(param.getAllMerge()==1){
if (param.getAllMerge() == 1) {
orderInfoService.remove(new QueryWrapper().eq(OrderInfo::getId, sourceOrder.getId()));
}
}
if(param.getAllMerge()==1){
if (param.getAllMerge() == 1) {
shopTableService.updateStatus(sourceOrder.getShopId(), null, sourceTableCode, ShopTableStatusEnum.IDLE.getValue());
}
shopTableService.updateStatus(sourceOrder.getShopId(), null, targetOrder.getTableCode(), ShopTableStatusEnum.UNSETTLED.getValue());
@@ -1028,7 +1036,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
*
* @param orderDetails 订单详情 需要回填
*/
private void processOrderDetails(List<OrderDetail> orderDetails, LimitRateDTO limitRate,OrderInfoAddDTO param) throws CzgException {
private void processOrderDetails(List<OrderDetail> orderDetails, LimitRateDTO limitRate, OrderInfoAddDTO param) throws CzgException {
BigDecimal packFee = BigDecimal.ZERO;
for (OrderDetail detail : orderDetails) {
if (!detail.getIsTemporary().equals(1) && detail.getProductId() > 0) {
@@ -1358,7 +1366,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
@Transactional
public void expired(Long orderId) {
OrderInfo orderInfo = orderInfoService.getById(orderId);
if(orderInfo == null){
if (orderInfo == null) {
log.info("订单取消失败,订单Id:{} 为空", orderId);
return;
}
@@ -1581,14 +1589,14 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
}
switch (orderInfoPrintDTO.getType()) {
case 0:
printerHandler.handler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.ONE_AND_ORDER);
case 0://菜品和结算单同时打印
printerHandler.orderHandler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.ONE_AND_ORDER, null);
break;
case 1:
printerHandler.handler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.PRE_ORDER);
case 1://预结算单
printerHandler.orderHandler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.PRE_ORDER, null);
break;
case 2:
printerHandler.handler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.ORDER);
case 2://结算单
printerHandler.orderHandler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.ORDER, null);
break;
}
return true;
@@ -1669,6 +1677,18 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
if (orderInfo.getPlaceNum().equals(1)) {
orderInfoService.updateById(new OrderInfo().setId(orderId)
.setStatus(OrderStatusEnums.CANCELLED.getCode()));
ShopTable table = shopTableService.getOneByTableCode(orderInfo.getShopId(), orderInfo.getTableCode());
if (table != null) {
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
if ("auto".equals(shopInfo.getTableClearType())) {
table.setStatus(ShopTableStatusEnum.IDLE.getValue());
} else {
DateTime dateTime = DateUtil.offsetMinute(DateUtil.date(), shopInfo.getTableClearTime());
table.setCreateTime(LocalDateTimeUtil.of(dateTime));
redisService.set(RedisCst.classKeyExpired.EXPIRED_TABLE + table.getId(), "", 60L * shopInfo.getTableClearTime());
}
shopTableService.updateById(table);
}
rabbitPublisher.sendOrderCancelMsg(orderInfo.getId().toString());
return true;
}
@@ -1690,6 +1710,18 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
orderInfoService.updateById(new OrderInfo().setId(orderId)
.setStatus(OrderStatusEnums.CANCELLED.getCode())
.setOriginAmount(BigDecimal.ZERO));
ShopTable table = shopTableService.getOneByTableCode(orderInfo.getShopId(), orderInfo.getTableCode());
if (table != null) {
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
if ("auto".equals(shopInfo.getTableClearType())) {
table.setStatus(ShopTableStatusEnum.IDLE.getValue());
} else {
DateTime dateTime = DateUtil.offsetMinute(DateUtil.date(), shopInfo.getTableClearTime());
table.setCreateTime(LocalDateTimeUtil.of(dateTime));
redisService.set(RedisCst.classKeyExpired.EXPIRED_TABLE + table.getId(), "", 60L * shopInfo.getTableClearTime());
}
shopTableService.updateById(table);
}
return true;
} else {
BigDecimal totalAmount = BigDecimal.ZERO;
@@ -1702,8 +1734,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
} else {
unitPrice = orderDetail.getPrice();
}
totalAmount = totalAmount.add((orderDetail.getNum().subtract(orderDetail.getReturnNum())))
.multiply(unitPrice);
totalAmount = totalAmount.add((orderDetail.getNum().subtract(orderDetail.getReturnNum())).multiply(unitPrice));
}
if (subtract.compareTo(BigDecimal.ZERO) > 0
&& orderDetail.getPackAmount().compareTo(BigDecimal.ZERO) > 0

View File

@@ -44,6 +44,7 @@ import com.czg.resp.CzgResult;
import com.czg.service.RedisService;
import com.czg.service.order.dto.OrderPayParamDTO;
import com.czg.service.order.enums.OrderStatusEnums;
import com.czg.service.order.print.PrinterHandler;
import com.czg.service.order.service.OrderPayService;
import com.czg.service.order.service.PayService;
import com.czg.utils.AssertUtil;
@@ -93,6 +94,8 @@ public class OrderPayServiceImpl implements OrderPayService {
@Resource
private RabbitPublisher rabbitPublisher;
@Resource
private PrinterHandler printerHandler;
@Resource
private MkShopRechargeService shopRechargeService;
@Resource
private MkShopRechargeDetailService shopRechargeDetailService;
@@ -402,12 +405,19 @@ public class OrderPayServiceImpl implements OrderPayService {
//退款数量
BigDecimal refNum = refundDetail.getNum();
OrderDetail orderDetail = orderDetailService.getById(refundDetail.getId());
if (orderDetail == null) {
throw new CzgException("退单失败,订单明细不存在");
}
refundDetail.setProductName(orderDetail.getProductName());
refundDetail.setSkuName(orderDetail.getSkuName());
//可退数量=订单数量-退单数量-退菜数量
BigDecimal returnNum = orderDetail.getNum().subtract(orderDetail.getRefundNum()).subtract(orderDetail.getReturnNum());
if (returnNum.compareTo(BigDecimal.ZERO) <= 0 || returnNum.compareTo(refundDetail.getNum()) < 0) {
throw new CzgException("退单失败," + orderDetail.getProductName() + "可退数量不足");
}
refundDetail.setReturnAmount(refundDetail.getNum().multiply(orderDetail.getUnitPrice()).setScale(2, RoundingMode.UP));
BigDecimal yuanReturnAmount = orderDetail.getReturnAmount();
if (isPay) {
orderDetail.setRefundNum(orderDetail.getRefundNum().add(refNum));
if (orderDetail.getNum().compareTo(orderDetail.getRefundNum().add(orderDetail.getReturnNum())) == 0) {
@@ -426,6 +436,7 @@ public class OrderPayServiceImpl implements OrderPayService {
orderDetail.setRefundRemark(orderDetail.getRefundRemark() + param.getRefundReason());
if (orderDetail.getReturnAmount().compareTo(orderDetail.getPayAmount()) > 0) {
orderDetail.setReturnAmount(orderDetail.getPayAmount());
refundDetail.setReturnAmount(orderDetail.getPayAmount().subtract(yuanReturnAmount));
}
orderDetailService.updateById(orderDetail);
if (orderDetail.getProductId() != null && orderDetail.getProductId() > 0) {
@@ -439,8 +450,7 @@ public class OrderPayServiceImpl implements OrderPayService {
} else if (isPay) {
orderInfo.setStatus(OrderStatusEnums.REFUND.getCode());
}
}
else {
} else {
orderInfo.setStatus(OrderStatusEnums.REFUND.getCode());
List<OrderDetail> orderDetails = orderDetailService.list(
QueryWrapper.create().select(OrderDetail::getId, OrderDetail::getProductId, OrderDetail::getNum, OrderDetail::getReturnNum, OrderDetail::getPackAmount, OrderDetail::getReturnNum)
@@ -464,8 +474,10 @@ public class OrderPayServiceImpl implements OrderPayService {
orderDetailService.updateBatch(orderDetails);
}
//总退款金额
String printTitle = "退菜单";
//TODO 退款 券 未处理
if (isPay) {
printTitle = "退款单";
orderInfo.setRefundType("cash");
//非现金退款
if (!param.isCash()) {
@@ -497,7 +509,10 @@ 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 (!returnProMap.isEmpty()) {
rabbitPublisher.sendOrderRefundMsg(JSONObject.toJSONString(Map.of("orderId", orderInfo.getId(), "returnProMap", returnProMap)));

View File

@@ -176,6 +176,14 @@ 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) {
Long shopId = StpKit.USER.getShopId(0L);

View File

@@ -77,31 +77,31 @@ public class ProductRpcServiceImpl implements ProductRpcService {
if (product == null) {
continue;
}
// 商品开启库存
if (product.getIsStock() == SystemConstants.OneZero.ZERO) {
continue;
}
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;
// 商品开启库存
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;
}
}
// 查询商品绑定耗材信息
List<ProdConsRelation> relationList = prodConsRelationMapper.selectListByQuery(QueryWrapper.create().eq(ProdConsRelation::getProductId, dto.getProductId()));
if (CollUtil.isEmpty(relationList)) {
@@ -112,13 +112,13 @@ public class ProductRpcServiceImpl implements ProductRpcService {
Long consInfoId = prodConsRelation.getConsInfoId();
// 耗材消耗数量
BigDecimal surplusStock = prodConsRelation.getSurplusStock();
if (surplusStock == null) {
if (surplusStock == null || surplusStock.compareTo(BigDecimal.ZERO) == 0) {
continue;
}
// 实际消耗数量 = 耗材消耗数量 * 商品购买数量
surplusStock = NumberUtil.mul(surplusStock, dto.getNum());
ConsInfo consInfo = consInfoMapper.selectOneById(consInfoId);
if (consInfo == null) {
if (consInfo == null || consInfo.getIsStock() == SystemConstants.OneZero.ZERO) {
continue;
}
BigDecimal stockNumber = consInfo.getStockNumber();
@@ -239,43 +239,33 @@ public class ProductRpcServiceImpl implements ProductRpcService {
if (CollUtil.isEmpty(list)) {
return;
}
log.info(">>>>>>>>>>>>>>>>>入参1{}", list.size());
boolean isLowWarnLine = false;
for (ProductStockSubtractDTO dto : list) {
Product product = productMapper.selectOneById(dto.getProductId());
log.info(">>>>>>>>>>>>>>>>>入参2{}", product.getName());
// 商品是否允许退款退货时归还库存
if (SystemConstants.OneZero.ZERO == product.getIsRefundStock()) {
continue;
}
// 商品未开启库存
if (SystemConstants.OneZero.ZERO == product.getIsStock()) {
continue;
}
log.info(">>>>>>>>>>>>>>>>>入参3{}", product.getName());
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());
log.info(">>>>>>>>>>>>>>>>>入参4{}", redisService.get(key));
refreshRedisProdStock(shopId, product.getId(), flow.getAfterNumber());
log.info(">>>>>>>>>>>>>>>>>入参5{}", redisService.get(key));
Integer warnLine = ObjUtil.defaultIfNull(product.getWarnLine(), 10);
if (!isLowWarnLine && (NumberUtil.isLessOrEqual(flow.getBeforeNumber(), BigDecimal.ZERO) || NumberUtil.isLess(flow.getAfterNumber(), Convert.toBigDecimal(warnLine)))) {
isLowWarnLine = true;
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()));
@@ -287,13 +277,13 @@ public class ProductRpcServiceImpl implements ProductRpcService {
Long consInfoId = prodConsRelation.getConsInfoId();
// 耗材消耗数量
BigDecimal surplusStock = prodConsRelation.getSurplusStock();
if (surplusStock == null) {
if (surplusStock == null || surplusStock.compareTo(BigDecimal.ZERO) == 0) {
continue;
}
// 实际消耗数量 = 耗材消耗数量 * 商品购买数量
surplusStock = NumberUtil.mul(surplusStock, dto.getNum());
ConsInfo consInfo = consInfoMapper.selectOneById(consInfoId);
if (consInfo == null) {
if (consInfo == null || consInfo.getIsStock() == SystemConstants.OneZero.ZERO || consInfo.getIsRefundStock() == SystemConstants.OneZero.ZERO) {
continue;
}
BigDecimal stockNumber = consInfo.getStockNumber();

View File

@@ -339,7 +339,9 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
Set<String> keys = redisService.rightLikeKey(prefix);
for (String key : keys) {
List<ProductDTO> prodList = redisService.getJsonToBeanList(key, ProductDTO.class);
list.addAll(prodList);
if(CollUtil.isNotEmpty(prodList)) {
list.addAll(prodList);
}
}
} else {
String key = prefix + param.getCategoryId();