diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..2bc79d8 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,127 @@ +# Release Notes + +## 2026-03-29 - 场馆入场计费逻辑重构 + +### 一、按时计费流程 + +``` +入场 join() + ├─ price = basePrice × 2 (2小时押金) + ├─ 返回 flg=2, 等待支付 + └─ 支付成功 → paySuccess() + └─ 创建订单 (orderSn=原始订单号, paying=0) + +出场 out() + ├─ actualCost = (minutes / 60) × basePrice (保留2位小数) + ├─ deposit = basePrice × 2 + ├─ difference = actualCost - deposit + │ + ├─ difference > 0 (需补费) + │ └─ 返回 flg=2, 等待支付 + │ └─ 支付成功 → paySuccess(enterFlag=OUT) + │ └─ 设置 orderAddSn=补费订单号, paying=2 + │ + ├─ difference < 0 (需退款) + │ └─ payMoney = |difference| (BigDecimal, 2位小数) + │ └─ paying=1, status=USED + │ └─ 用户可立即重新入场 + │ └─ 批处理退款 + │ + └─ difference = 0 (刚好) + └─ paying=2, status=USED + +批处理 refundOrder() + ├─ 扫描 paying=1 的订单 + ├─ 如果 orderAddSn 存在 → 跳过(补费订单) + ├─ 如果 orderAddSn 不存在 → 退款 + └─ 调用微信退款接口 (元转分) +``` + +### 二、按次计费流程 + +``` +入场 join() + ├─ price = basePrice (单次费用) + ├─ 返回 flg=2, 等待支付 + └─ 支付成功 → paySuccess() + └─ 创建订单 (orderSn=原始订单号, paying=0, 有效期=timePayHour) + +出场 out() + └─ paying=1, 10分钟宽限期 + +重新入场 join() + ├─ 如果 paying=1 且按次计费 → 重置 paying=0 + └─ 否则 → 已在场内 + +批处理 refundOrder() + ├─ 扫描 paying=1 的订单 + ├─ 按次计费: 10分钟后关闭订单 + └─ 按时计费: 立即退款(如果无补费记录) + +批处理 execute() + └─ order_end < now → 关闭订单 +``` + +### 三、管理员手动退费 + +``` +enterOrderAccount(enterId, payMoney) + ├─ 检查: paying != 1 (不能重复结算) + ├─ 检查: orderAddSn 为空 (不能退补费订单) + ├─ 检查: 退款金额 <= 原订单金额 + └─ 设置 paying=1, payMoney=指定金额 + └─ 等待批处理处理 +``` + +### 四、金额类型规范 + +| 位置 | 类型 | 精度 | 说明 | +|---|---|---|---| +| 数据库 pay_money | DECIMAL(10,2) | 2位小数 | | +| 数据库 sum_pay_money | DECIMAL(10,2) | 2位小数 | | +| 实体 BarcodeOrderTime.payMoney | BigDecimal | 2位小数 | | +| 实体 BarcodeOrderTime.sumPayMoney | BigDecimal | 2位小数 | | +| 微信支付接口 | Integer | 分 | 元×100 | +| 微信退款接口 | Integer | 分 | 元×100 | + +### 五、关键表字段变动 + +| 场景 | sv_barcode_order_time | sv_member_refund | sv_member_money_log | +|---|---|---|---| +| 入场支付成功 | order_sn=A, paying=0 | - | type=JOIN | +| 出场需退款 | paying=1, payMoney=退款额 | - | - | +| 批处理退款 | paying=0, status=USED | money=退款额 | type=REFUND | +| 出场需补费 | paying=1, payMoney=-1 | - | - | +| 补费支付成功 | order_add_sn=B, paying=2 | - | type=JOIN | +| 管理员退费 | paying=1, payMoney=指定额 | - | - | + +### 六、已修复的问题 + +| 问题 | 修复 | +|---|---| +| payMoney 类型 | Integer → BigDecimal | +| sumPayMoney 类型 | Integer → BigDecimal | +| XML 映射 | jdbcType INTEGER → DECIMAL | +| 金额比较 | \> 0 → compareTo(ZERO) > 0 | +| 金额计算 | int 加法 → BigDecimal.add() | +| 退款金额精度 | intValue() → setScale(2) | +| 退款金额单位混乱 | 统一为元,微信接口转分 | +| 补费订单退款 | 跳过不处理 | +| 管理员退费限制 | 有补费记录时拒绝 | +| 8小时兜底逻辑 | 删除(冗余) | +| 10分钟宽限期 | 只给按次计费 | +| 出场退款后无法立即入场 | 设置 status=USED,允许立即重新入场 | + +### 七、修改文件清单 + +| 文件 | 修改内容 | +|---|---| +| `BarcodeOrderTime.java` | payMoney, sumPayMoney: Integer → BigDecimal | +| `BarcodeOrderTimeMapper.xml` | jdbcType: INTEGER → DECIMAL | +| `VenueEnterService.java` | 重写 out() 按分钟计费;setPayMoney() 参数改为 BigDecimal | +| `OrderService.java` | setPayMoney(-1) → setPayMoney(new BigDecimal(-1)) | +| `MemberRefundService.java` | sumPayMoney 计算改为 BigDecimal.add() | +| `BarcodeTimeOrderTask.java` | 删除8小时兜底;getPayMoney() 比较改为 compareTo() | +| `ServerMessageHandlerAdapter.java` | getPayMoney() 比较改为 compareTo() | +| `MemberEnterVeneuLogController.java` | payMoney 参数改为 BigDecimal | +| `WechatPayService.java` | refundInputMoney() 方法签名改为接收原订单金额和退款金额 | diff --git a/api/src/main/java/com/sv/netty/netty/service/impl/ServerMessageHandlerAdapter.java b/api/src/main/java/com/sv/netty/netty/service/impl/ServerMessageHandlerAdapter.java index 1f38aa9..d82b827 100644 --- a/api/src/main/java/com/sv/netty/netty/service/impl/ServerMessageHandlerAdapter.java +++ b/api/src/main/java/com/sv/netty/netty/service/impl/ServerMessageHandlerAdapter.java @@ -187,7 +187,7 @@ public class ServerMessageHandlerAdapter implements MessageService { BarcodeOrderTime lastOrder = barcodeOrderTimeMapper.findLastOrder(member.getId(), venueBarCode.getVenueId()); lastOrder.setLastOut(new Date()); // 不需要补交钱且需要退钱 - if (lastOrder.getPayMoney() != null && lastOrder.getPayMoney() > 0) { + if (lastOrder.getPayMoney() != null && lastOrder.getPayMoney().compareTo(java.math.BigDecimal.ZERO) > 0) { lastOrder.setModifiedTime(new Date()); } barcodeOrderTimeMapper.updateByPrimaryKey(lastOrder); diff --git a/api/src/test/java/com/sv/wx/WxServiceTest.java b/api/src/test/java/com/sv/wx/WxServiceTest.java index ddb3fb2..edc95aa 100644 --- a/api/src/test/java/com/sv/wx/WxServiceTest.java +++ b/api/src/test/java/com/sv/wx/WxServiceTest.java @@ -42,15 +42,14 @@ public class WxServiceTest { MemberRefund memberRefund = new MemberRefund(); memberRefund.setMemberId(memberId); memberRefund.setLessonId(1); - memberRefund.setMoney(order.getPrice()); -// memberRefund.setMoney(new BigDecimal(0.01)); + memberRefund.setMoney(new BigDecimal(0.01)); memberRefund.setOrderSn(orderSn); memberRefund.setTransactionId(order.getTradeSn()); memberRefund.setOrderId(order.getId()); memberRefund.setOutRefundNo(orderService.createSn());//商户退款单号 memberRefund.setPlatformId(1); memberRefundMapper.insert(memberRefund); - wechatPayService.refundInputMoney(memberRefund,new BigDecimal(0.01)); + wechatPayService.refundInputMoney(memberRefund, order.getPrice(), new BigDecimal(0.01)); } diff --git a/entity/src/main/java/com/sv/entity/BarcodeOrderTime.java b/entity/src/main/java/com/sv/entity/BarcodeOrderTime.java index 70b6253..cbe9166 100644 --- a/entity/src/main/java/com/sv/entity/BarcodeOrderTime.java +++ b/entity/src/main/java/com/sv/entity/BarcodeOrderTime.java @@ -1,5 +1,6 @@ package com.sv.entity; +import java.math.BigDecimal; import java.util.Date; public class BarcodeOrderTime { @@ -36,12 +37,12 @@ public class BarcodeOrderTime { /** * 退款金额 -1 代表出场还需要交钱 */ - private Integer payMoney; + private BigDecimal payMoney; /** * 总退款金额 */ - private Integer sumPayMoney; + private BigDecimal sumPayMoney; private String orderSn; @@ -51,7 +52,7 @@ public class BarcodeOrderTime { private String orderAddSn; public BarcodeOrderTime(Integer id, Integer memberId, Integer venueId, Date createdTime, Date modifiedTime, Date orderStart, Date orderEnd, Date lastEnter, Date lastOut, Integer status ,Integer paying, - Integer payMoney, Integer sumPayMoney, String orderSn, String orderAddSn) { + BigDecimal payMoney, BigDecimal sumPayMoney, String orderSn, String orderAddSn) { this.id = id; this.memberId = memberId; this.venueId = venueId; @@ -145,11 +146,11 @@ public class BarcodeOrderTime { this.paying = paying; } - public Integer getPayMoney() { + public BigDecimal getPayMoney() { return payMoney; } - public void setPayMoney(Integer payMoney) { + public void setPayMoney(BigDecimal payMoney) { this.payMoney = payMoney; } @@ -185,11 +186,11 @@ public class BarcodeOrderTime { this.lastOut = lastOut; } - public Integer getSumPayMoney() { + public BigDecimal getSumPayMoney() { return sumPayMoney; } - public void setSumPayMoney(Integer sumPayMoney) { + public void setSumPayMoney(BigDecimal sumPayMoney) { this.sumPayMoney = sumPayMoney; } } diff --git a/netty-client/src/main/java/com/sv/intergration/impl/OldDoorService.java b/netty-client/src/main/java/com/sv/intergration/impl/OldDoorService.java index 7d5d650..97ec131 100644 --- a/netty-client/src/main/java/com/sv/intergration/impl/OldDoorService.java +++ b/netty-client/src/main/java/com/sv/intergration/impl/OldDoorService.java @@ -1,37 +1,81 @@ package com.sv.intergration.impl; import Net.PC15.Command.CommandDetial; +import Net.PC15.Command.INCommand; +import Net.PC15.Command.INCommandResult; import Net.PC15.Connector.ConnectorAllocator; +import Net.PC15.Connector.ConnectorDetial; import Net.PC15.Connector.E_ControllerType; +import Net.PC15.Connector.INConnectorEvent; import Net.PC15.Connector.TCPClient.TCPClientDetial; +import Net.PC15.Data.INData; import Net.PC15.FC8800.Command.Door.OpenDoor; import Net.PC15.FC8800.Command.Door.Parameter.OpenDoor_Parameter; import Net.PC15.FC8800.FC8800Identity; import com.sv.intergration.DoorService; import com.sv.netty.config.NettyConstant; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; +import com.sv.netty.utils.JsonUtils; public class OldDoorService implements DoorService { + private static INConnectorEvent listener; + + static { + listener = new INConnectorEvent() { + @Override + public void CommandCompleteEvent(INCommand inCommand, INCommandResult inCommandResult) { + logger.info("CommandCompleteEvent open door success"); + } + + @Override + public void CommandProcessEvent(INCommand inCommand) { + logger.info("CommandProcessEvent open door ..."); + } + + @Override + public void ConnectorErrorEvent(INCommand inCommand, boolean b) { + logger.info("CommandProcessEvent open door ... the bool is " + b); + } + + @Override + public void ConnectorErrorEvent(ConnectorDetial connectorDetial) { + logger.error("ConnectorErrorEvent open door error"); + } + + @Override + public void CommandTimeout(INCommand inCommand) { + logger.error("CommandTimeout open door time out"); + } + + @Override + public void PasswordErrorEvent(INCommand inCommand) { + logger.error("PasswordErrorEvent open door password error"); + } + + @Override + public void ChecksumErrorEvent(INCommand inCommand) { + logger.error("ChecksumErrorEvent open door error"); + } + + @Override + public void WatchEvent(ConnectorDetial connectorDetial, INData inData) { + logger.error("WatchEvent open door ..."); + } + }; + } + @Override public void enterOpenDoor() { - opendoor(1); + openDoor(1); } @Override public void outOpenDoor() { - opendoor(2); + openDoor(2); } - private void opendoor(int doorSn) { + private void openDoor(int doorSn) { try { - // 1. 先检查网络连通性(Java 层) - if (!isNetworkReachable("192.168.1.150", 8000, 2000)) { - throw new RuntimeException("net socket error: 192.168.1.150:8000"); - } ConnectorAllocator connector = ConnectorAllocator.GetAllocator(); TCPClientDetial tcpClientDetial = new TCPClientDetial("192.168.1.150", Integer.valueOf("8000")); connector.GetCommandCount(tcpClientDetial); @@ -39,29 +83,16 @@ public class OldDoorService implements DoorService { CommandDetial detial = new CommandDetial(); detial.Connector = tcpClientDetial; String clientSn = System.getProperty(NettyConstant.VENUE_CLIENT_SN); -// detial.Identity = new FC8800Identity("MC-5824T23014127", "12345678", E_ControllerType.FC8900); detial.Identity = new FC8800Identity(clientSn, "12345678", E_ControllerType.FC8900); OpenDoor_Parameter openDoorParameter = new OpenDoor_Parameter(detial); openDoorParameter.Door.SetDoor(doorSn, 1); - - for (int i = 0; i < 3; i++) { - logger.info("{} times to try...", i + 1); - boolean connected = connector.IsForciblyConnect(tcpClientDetial); - - if (connected) { - logger.info("[{}] connected"); - break; - } - - logger.warn("[{}] times to try, trying", i + 1); - Thread.sleep(1000); // 等待 1 秒后重试 - } - OpenDoor openDoor = new OpenDoor(openDoorParameter); boolean command = connector.AddCommand(openDoor); if (!command) { logger.error("sn-{} door open command exec fail",doorSn); } + connector.AddListener(listener); + System.out.println(connector.IsRelease()); if (openDoor.getIsTimeout()) { logger.info("----sn-{} open door timeout ----",doorSn); } @@ -70,15 +101,4 @@ public class OldDoorService implements DoorService { } } - // 网络连通性检查(Java 层) - private boolean isNetworkReachable(String host, int port, int timeoutMs) { - try (Socket socket = new Socket()) { - socket.connect(new InetSocketAddress(host, port), timeoutMs); - return true; - } catch (IOException e) { - logger.error("net link error: {}:{} - {}", host, port, e.getMessage()); - return false; - } - } - } diff --git a/oms/src/main/java/com/sv/oms/controller/MemberEnterVeneuLogController.java b/oms/src/main/java/com/sv/oms/controller/MemberEnterVeneuLogController.java index 7e1faa0..c4c20e2 100644 --- a/oms/src/main/java/com/sv/oms/controller/MemberEnterVeneuLogController.java +++ b/oms/src/main/java/com/sv/oms/controller/MemberEnterVeneuLogController.java @@ -1,9 +1,11 @@ package com.sv.oms.controller; import com.sv.entity.MemberEnterVenueLog; +import com.sv.exception.oms.OmsException; import com.sv.service.api.VenueEnterService; import com.sv.service.oms.MemberEnterVenueLogService; import com.ydd.framework.core.common.Pagination; import com.ydd.framework.core.common.dto.ResponseDTO; +import com.ydd.framework.core.exception.ServiceException; import com.ydd.oms.controller.OmsController; import org.slf4j.Logger; @@ -84,8 +86,14 @@ public class MemberEnterVeneuLogController extends OmsController { } @RequestMapping(value = "/member/enter/veneu/account", method = RequestMethod.POST) - public ResponseDTO enterOrderAccount(@RequestParam("EnterId") Integer enterId,@RequestParam("payMoney") Integer payMoney) { - venueEnterService.enterOrderAccount(enterId,payMoney); + public ResponseDTO enterOrderAccount(@RequestParam("EnterId") Integer enterId,@RequestParam("payMoney") java.math.BigDecimal payMoney) { + try { + venueEnterService.enterOrderAccount(enterId,payMoney); + }catch (Exception e) { + if (e instanceof ServiceException) { + throw new OmsException(e.getMessage()); + } + } return ResponseDTO.ok("结算成功"); } diff --git a/oms/src/main/java/com/ydd/oms/task/BarcodeTimeOrderTask.java b/oms/src/main/java/com/ydd/oms/task/BarcodeTimeOrderTask.java index f15d427..aaa4c27 100644 --- a/oms/src/main/java/com/ydd/oms/task/BarcodeTimeOrderTask.java +++ b/oms/src/main/java/com/ydd/oms/task/BarcodeTimeOrderTask.java @@ -10,6 +10,7 @@ import com.sv.mapper.OrderMapper; import com.sv.service.api.config.WechatPayService; import com.sv.service.api.util.DateUtilCard; import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateFormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,7 +42,7 @@ public class BarcodeTimeOrderTask { @Resource WechatPayService wechatPayService; - @Scheduled(cron = "0 0/5 * * * ?") + @Scheduled(cron = "0 0/8 * * * ?") public void execute(){ logger.error("执行BarcodeTimeOrderTask.execute"); Date date = new Date(); @@ -56,15 +57,15 @@ public class BarcodeTimeOrderTask { } } - @Scheduled(cron = "0 0/2 * * * ?") + @Scheduled(cron = "0 0/5 * * * ?") public void refundOrder(){ logger.error("执行BarcodeTimeOrderTask.refundOrder"); List barcodeOrderTimes = barcodeOrderTimeMapper.needPayOrderList(); if (barcodeOrderTimes != null && barcodeOrderTimes.size() > 0){ Date date = new Date(); for (BarcodeOrderTime barcodeOrderTime : barcodeOrderTimes) { - boolean isHourlyRefund = barcodeOrderTime.getPayMoney() != null && barcodeOrderTime.getPayMoney() > 0; - + boolean isHourlyRefund = barcodeOrderTime.getPayMoney() != null && barcodeOrderTime.getPayMoney().compareTo(BigDecimal.ZERO) > 0; + if (!isHourlyRefund) { // 按次计费:10分钟宽限期 int minutes = DateUtilCard.diffMinute(barcodeOrderTime.getModifiedTime(), date); @@ -72,29 +73,35 @@ public class BarcodeTimeOrderTask { continue; } } - + // 关闭订单 barcodeOrderTime.setPaying(0); barcodeOrderTime.setModifiedTime(date); barcodeOrderTime.setStatus(BarCodeStatusEnum.USED.getValue()); barcodeOrderTimeMapper.updateByPrimaryKey(barcodeOrderTime); - + // 按时计费退款 if (isHourlyRefund) { + // 如果有补费订单号,跳过退款(与管理员退费逻辑一致) + if (!StringUtils.isEmpty(barcodeOrderTime.getOrderAddSn())) { + logger.info("用户" + barcodeOrderTime.getMemberId() + "的订单有补费记录,跳过退款"); + continue; + } Order order = orderMapper.findOrderSn(barcodeOrderTime.getOrderSn(), barcodeOrderTime.getMemberId()); if (order != null) { - logger.info("用户" + barcodeOrderTime.getMemberId() + "的订单" + barcodeOrderTime.getOrderSn() + "需要退款" + barcodeOrderTime.getPayMoney()); + BigDecimal refundAmount = barcodeOrderTime.getPayMoney(); + logger.info("用户" + barcodeOrderTime.getMemberId() + "的订单" + barcodeOrderTime.getOrderSn() + "需要退款" + refundAmount + "元"); MemberRefund memberRefund = new MemberRefund(); memberRefund.setMemberId(barcodeOrderTime.getMemberId()); memberRefund.setLessonId(barcodeOrderTime.getId()); - memberRefund.setMoney(order.getPrice()); + memberRefund.setMoney(refundAmount); memberRefund.setOrderSn(barcodeOrderTime.getOrderSn()); memberRefund.setTransactionId(order.getTradeSn()); memberRefund.setOrderId(order.getId()); memberRefund.setOutRefundNo(createSn()); memberRefund.setPlatformId(1); memberRefundMapper.insert(memberRefund); - wechatPayService.refundInputMoney(memberRefund,new BigDecimal(barcodeOrderTime.getPayMoney())); + wechatPayService.refundInputMoney(memberRefund, order.getPrice(), refundAmount); } } } diff --git a/service/src/main/java/com/sv/service/api/MemberRefundService.java b/service/src/main/java/com/sv/service/api/MemberRefundService.java index e2b8cd9..0e4a565 100644 --- a/service/src/main/java/com/sv/service/api/MemberRefundService.java +++ b/service/src/main/java/com/sv/service/api/MemberRefundService.java @@ -2,6 +2,7 @@ package com.sv.service.api; import com.enums.MoneyLogEnum; import com.enums.PayTypeEnum; +import com.enums.VenueTypeEnum; import com.github.pagehelper.PageHelper; import com.sv.dto.api.MemberLessonTicketDetailDTO; import com.sv.dto.api.wechat.BaseResult; @@ -22,6 +23,7 @@ import org.springframework.web.bind.annotation.RequestBody; import javax.annotation.Resource; import java.io.IOException; +import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; @@ -184,24 +186,24 @@ public class MemberRefundService extends BaseServiceImpl { memberRefund.setSuccessTime(time); memberRefundMapper.update(memberRefund); + Integer venueType = null; // 如果是球场订单(更新总退款金额) add by limqsh BarcodeOrderTime barcodeOrderTime = barcodeOrderTimeMapper.selectByPrimaryKey(memberRefund.getLessonId()); if (barcodeOrderTime != null) { + venueType = VenueTypeEnum.BASKETBALL.value; if (barcodeOrderTime.getOrderSn() != null && barcodeOrderTime.getOrderSn().equals(memberRefund.getOrderSn())) { - barcodeOrderTime.setSumPayMoney( - (barcodeOrderTime.getSumPayMoney() == null ? 0 : barcodeOrderTime.getSumPayMoney()) - + memberRefund.getMoney().intValue()); - barcodeOrderTime.setPayMoney(0); + BigDecimal currentSumPayMoney = barcodeOrderTime.getSumPayMoney() == null ? BigDecimal.ZERO : barcodeOrderTime.getSumPayMoney(); + barcodeOrderTime.setSumPayMoney(currentSumPayMoney.add(memberRefund.getMoney())); + barcodeOrderTime.setPayMoney(BigDecimal.ZERO); barcodeOrderTime.setModifiedTime(new Date()); barcodeOrderTimeMapper.updateByPrimaryKey(barcodeOrderTime); } } // 如果是球场订单(更新总退款金额) add by limqsh end - // 记录到‘用户账单(余额,微信,会员卡)记录’ memberMoneyLogService.create(memberRefund.getMemberId(),platformId,MoneyLogEnum.REFUND.value,memberRefund.getMoney(),PayTypeEnum.WEI_XIN.value, - null,null,null,memberRefund.getLessonId()); + null,null,venueType,memberRefund.getLessonId()); }catch (Exception e){ e.printStackTrace(); } diff --git a/service/src/main/java/com/sv/service/api/OrderService.java b/service/src/main/java/com/sv/service/api/OrderService.java index 7328824..19b96e8 100644 --- a/service/src/main/java/com/sv/service/api/OrderService.java +++ b/service/src/main/java/com/sv/service/api/OrderService.java @@ -297,7 +297,7 @@ public class OrderService extends BaseServiceImpl { BarcodeOrderTime lastOrder = barcodeOrderTimeMapper.findLastOrder(memberId, venueId); if (lastOrder != null) { lastOrder.setPaying(1); - lastOrder.setPayMoney(-1); + lastOrder.setPayMoney(new BigDecimal(-1)); lastOrder.setOrderAddSn(order.getOrderSn()); // lastOrder.setOrderSn(order.getOrderSn()); lastOrder.setModifiedTime(new Date()); diff --git a/service/src/main/java/com/sv/service/api/VenueEnterService.java b/service/src/main/java/com/sv/service/api/VenueEnterService.java index 56716ff..6e0502d 100644 --- a/service/src/main/java/com/sv/service/api/VenueEnterService.java +++ b/service/src/main/java/com/sv/service/api/VenueEnterService.java @@ -167,8 +167,9 @@ public class VenueEnterService extends BaseServiceImpl { result.setMsg("您此次入场" + minutes + "分钟,实际费用" + actualCost + "元,需补交" + difference + "元"); } else if (difference.compareTo(BigDecimal.ZERO) < 0) { BigDecimal refundAmount = difference.abs(); - lastOrder.setPayMoney(refundAmount.multiply(new BigDecimal(100)).intValue()); + lastOrder.setPayMoney(refundAmount.setScale(2, BigDecimal.ROUND_HALF_UP)); lastOrder.setPaying(1); + lastOrder.setStatus(BarCodeStatusEnum.USED.getValue()); lastOrder.setModifiedTime(new Date()); barcodeOrderTimeMapper.updateByPrimaryKey(lastOrder); result.setFlg(0); @@ -272,13 +273,13 @@ public class VenueEnterService extends BaseServiceImpl { Venue venue = venueMapper.findById(venueId); createMemberMoneyLog(MoneyLogEnum.JOIN.value, order.getPrice(), memberId, order.getPlatformId(), PayTypeEnum.WEI_XIN.value, null,venue.getId(), venue.getType()); if (EnterEnum.OUT.value != enterFlag) { - Integer timePayHour = 2; // 此处修改押金小时数 + Integer timePayHour = 8; // 此处修改押金小时数 if(PayStyleEnum.TIME.getValue() == venue.getPayStyle()){ // 按次入场先收钱,且多久不收钱,出场不收钱 // 该用户上次订单的是否逾期 timePayHour = venue.getTimePayHour(); if (timePayHour == null) { - timePayHour = 4; + timePayHour = 8; } } createBarcodeTimeOrder(memberId,venueId,timePayHour,order.getOrderSn()); @@ -338,7 +339,7 @@ public class VenueEnterService extends BaseServiceImpl { return memberEnterOrderDTO; } - public void enterOrderAccount(Integer enterId, Integer payMoney) { + public void enterOrderAccount(Integer enterId, BigDecimal payMoney) { logger.info("手动结算【" + enterId + "】,结算金额为:" + payMoney); BarcodeOrderTime barcodeOrder = barcodeOrderTimeMapper.selectByPrimaryKey(enterId); if (barcodeOrder == null) { @@ -347,7 +348,7 @@ public class VenueEnterService extends BaseServiceImpl { if (1 == barcodeOrder.getPaying()) { throw new ServiceException("订单正在结算,无法结算!"); } - if (payMoney <=0 ) { + if (payMoney.compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("退款金额不能为负数!"); } String orderSn = barcodeOrder.getOrderSn(); @@ -356,11 +357,12 @@ public class VenueEnterService extends BaseServiceImpl { throw new ServiceException("订单多次支付(使用超时),无法进行退款!"); } Order baseOrder = orderMapper.findByOrderSn(orderSn); - if ((barcodeOrder.getSumPayMoney() == null ? 0 : barcodeOrder.getSumPayMoney() + payMoney) > baseOrder.getPrice().intValue()) { + BigDecimal currentSumPayMoney = barcodeOrder.getSumPayMoney() == null ? BigDecimal.ZERO : barcodeOrder.getSumPayMoney(); + if (currentSumPayMoney.add(payMoney).compareTo(baseOrder.getPrice()) > 0) { throw new ServiceException("退款金额不能超过总支付金额!"); } barcodeOrder.setPaying(1); - barcodeOrder.setPayMoney(payMoney); // 此次支付金额 + barcodeOrder.setPayMoney(payMoney); logger.info("手动结算【" + enterId + "】,结算金额为:" + payMoney + "成功!"); barcodeOrderTimeMapper.updateByPrimaryKey(barcodeOrder); } diff --git a/service/src/main/java/com/sv/service/api/config/WechatPayService.java b/service/src/main/java/com/sv/service/api/config/WechatPayService.java index 15bc736..48e5ed2 100644 --- a/service/src/main/java/com/sv/service/api/config/WechatPayService.java +++ b/service/src/main/java/com/sv/service/api/config/WechatPayService.java @@ -261,13 +261,14 @@ public class WechatPayService extends BaseServiceImpl { } /** - * 退款接口 + * 退款接口(支持部分退款) + * @param memberRefund 退款记录 + * @param originalAmount 原始订单金额(元) + * @param refundAmount 退款金额(元) */ @Transactional - public void refundInputMoney(MemberRefund memberRefund,BigDecimal aMoney){ - OrderPaySignResponse.WechatPayParam wechatPayParam; + public void refundInputMoney(MemberRefund memberRefund, BigDecimal originalAmount, BigDecimal refundAmount){ try { - PayConfig payConfig = payConfigService.findKey("face"); Assert.hasText(payConfig.getCert(), "证书找不到"); String nonceStr = CommonUtils.CreateNonceStr(30); @@ -275,21 +276,18 @@ public class WechatPayService extends BaseServiceImpl { weChatPayHelper.setAppId(payConfig.getAppId()); weChatPayHelper.setMchId(payConfig.getMchId()); weChatPayHelper.setKey(payConfig.getKey()); - Integer payMoney = Integer.valueOf(memberRefund.getMoney().multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).toString()); - Integer refundMoney = Integer.valueOf(aMoney.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).toString()); + // 元转分 + Integer payMoney = originalAmount.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).intValue(); + Integer refundMoney = refundAmount.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).intValue(); weChatPayHelper.setParameter("notify_url", payConfig.getNotifyUrl()); - logger.info("申请退款请求参数" + ToStringBuilder.reflectionToString(weChatPayHelper)); - // 调用申请退款 -// String notifyUrl = "https://api.smartvenue.ydd100.cn//weixin/order/refund"; + logger.info("申请退款,原订单金额:" + originalAmount + "元,退款金额:" + refundAmount + "元"); OrderResponse response = weChatPayHelper.refund("",memberRefund.getOrderSn(),memberRefund.getOutRefundNo(),payMoney,refundMoney,payConfig.getCancel()); logger.info(ToStringBuilder.reflectionToString(response)); - System.out.println(ToStringBuilder.reflectionToString(response)); if (response.isSuccess()) { String refundId = response.getRefundId(); - //更新‘用户退款记录表’中微信退款单号 memberRefund.setRefundId(refundId); - memberRefund.setMoney(aMoney); + memberRefund.setMoney(refundAmount); memberRefundService.update(memberRefund); }else{ logger.error("返回的结果为:"+ToStringBuilder.reflectionToString(response)); diff --git a/service/src/main/resources/mybatis/mapper/sv/BarcodeOrderTimeMapper.xml b/service/src/main/resources/mybatis/mapper/sv/BarcodeOrderTimeMapper.xml index 8eac73b..91e99f9 100644 --- a/service/src/main/resources/mybatis/mapper/sv/BarcodeOrderTimeMapper.xml +++ b/service/src/main/resources/mybatis/mapper/sv/BarcodeOrderTimeMapper.xml @@ -14,8 +14,8 @@ - - + + @@ -40,7 +40,7 @@ values (#{id,jdbcType=INTEGER}, #{memberId,jdbcType=INTEGER}, #{venueId,jdbcType=INTEGER}, #{createdTime,jdbcType=TIMESTAMP}, #{modifiedTime,jdbcType=TIMESTAMP}, #{orderStart,jdbcType=TIMESTAMP}, #{orderEnd,jdbcType=TIMESTAMP}, #{lastEnter,jdbcType=TIMESTAMP}, #{lastOut,jdbcType=TIMESTAMP}, #{status,jdbcType=INTEGER}, - #{paying,jdbcType=INTEGER},#{payMoney,jdbcType=INTEGER}, #{sumPayMoney,jdbcType=INTEGER}, + #{paying,jdbcType=INTEGER},#{payMoney,jdbcType=DECIMAL}, #{sumPayMoney,jdbcType=DECIMAL}, #{orderSn,jdbcType=VARCHAR},#{orderAddSn,jdbcType=VARCHAR}) @@ -127,10 +127,10 @@ #{paying,jdbcType=INTEGER}, - #{payMoney,jdbcType=INTEGER}, + #{payMoney,jdbcType=DECIMAL}, - #{sumPayMoney,jdbcType=INTEGER}, + #{sumPayMoney,jdbcType=DECIMAL}, #{orderSn,jdbcType=VARCHAR}, @@ -174,10 +174,10 @@ paying = #{paying,jdbcType=INTEGER}, - pay_money = #{payMoney,jdbcType=INTEGER}, + pay_money = #{payMoney,jdbcType=DECIMAL}, - sum_pay_money = #{sumPayMoney,jdbcType=INTEGER}, + sum_pay_money = #{sumPayMoney,jdbcType=DECIMAL}, order_sn = #{orderSn,jdbcType=VARCHAR}, @@ -200,11 +200,11 @@ last_out = #{lastOut,jdbcType=TIMESTAMP}, status = #{status,jdbcType=INTEGER}, paying = #{paying,jdbcType=INTEGER}, - pay_money = #{payMoney,jdbcType=INTEGER}, - sum_pay_money = #{sumPayMoney,jdbcType=INTEGER}, + pay_money = #{payMoney,jdbcType=DECIMAL}, + sum_pay_money = #{sumPayMoney,jdbcType=DECIMAL}, order_sn = #{orderSn,jdbcType=VARCHAR}, order_add_sn = #{orderAddSn,jdbcType=VARCHAR} - where id = #{id,jdbcType=VARCHAR} + where id = #{id,jdbcType=INTEGER}