| | |
| | | import com.doumee.core.utils.DateUtil; |
| | | import com.doumee.core.utils.geocode.MapUtil; |
| | | import com.doumee.core.utils.Utils; |
| | | import com.doumee.core.utils.aliyun.AliSmsService; |
| | | import com.doumee.dao.business.*; |
| | | import com.doumee.dao.business.model.*; |
| | | import com.doumee.dao.system.SystemUserMapper; |
| | |
| | | import com.github.xiaoymin.knife4j.core.util.CollectionUtils; |
| | | import com.github.yulichang.wrapper.MPJLambdaWrapper; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.redis.core.RedisTemplate; |
| | |
| | | * @author rk |
| | | * @date 2026/04/10 |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class OrdersServiceImpl implements OrdersService { |
| | | |
| | |
| | | |
| | | @Autowired |
| | | private NoticeService noticeService; |
| | | |
| | | @Autowired |
| | | private SmsrecordMapper smsrecordMapper; |
| | | |
| | | @Autowired |
| | | private WxPayV3Service wxPayV3Service; |
| | |
| | | queryWrapper.eq(pageWrap.getModel().getTakeShopId() != null, Orders::getTakeShopId, pageWrap.getModel().getTakeShopId()); |
| | | queryWrapper.and(pageWrap.getModel().getDriverKeyword() != null, i->i.like(DriverInfo::getName, pageWrap.getModel().getDriverKeyword()) |
| | | .or().like(DriverInfo::getTelephone, pageWrap.getModel().getDriverKeyword())); |
| | | queryWrapper.eq(pageWrap.getModel().getSettlementStatus() != null, Orders::getSettlementStatus, pageWrap.getModel().getSettlementStatus()); |
| | | for (PageWrap.SortData sortData : pageWrap.getSorts()) { |
| | | if (sortData.getDirection().equalsIgnoreCase(PageWrap.DESC)) { |
| | | queryWrapper.orderByDesc(sortData.getProperty()); |
| | |
| | | queryWrapper.eq(pageWrap.getModel().getTakeShopId() != null, Orders::getTakeShopId, pageWrap.getModel().getTakeShopId()); |
| | | queryWrapper.and(pageWrap.getModel().getDriverKeyword() != null, i->i.like(DriverInfo::getName, pageWrap.getModel().getDriverKeyword()) |
| | | .or().like(DriverInfo::getTelephone, pageWrap.getModel().getDriverKeyword())); |
| | | queryWrapper.eq(pageWrap.getModel().getSettlementStatus() != null, Orders::getSettlementStatus, pageWrap.getModel().getSettlementStatus()); |
| | | |
| | | queryWrapper.select( |
| | | "IFNULL(SUM(t.total_amount), 0) as total_amount_sum", |
| | |
| | | if (takeShop == null || Constants.equalsInteger(takeShop.getDeleted(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "取件店铺不存在"); |
| | | } |
| | | if (takeShop.getStatus() == null || !Constants.equalsInteger(takeShop.getStatus(), Constants.ONE)) { |
| | | if (takeShop.getStatus() == null || Constants.equalsInteger(takeShop.getStatus(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "取件店铺已停业,请选择其他门店"); |
| | | } |
| | | takeLat = BigDecimal.valueOf(takeShop.getLatitude()); |
| | |
| | | // 薪酬计算与占比存储 |
| | | calculateAndSetFeeAllocation(orders, depositShop, takeShop); |
| | | |
| | | // 无人接单通知相关初始化 |
| | | orders.setPlatformSmsNotified(Constants.ZERO); |
| | | orders.setPlatformSmsNotifiedTime(now); |
| | | |
| | | ordersMapper.insert(orders); |
| | | Integer orderId = orders.getId(); |
| | | |
| | |
| | | // 5. 重新生成第三方订单编号(避免重复) |
| | | String orderTradeNo = generateOrderTradeNo(); |
| | | orders.setOutTradeNo(orderTradeNo); |
| | | orders.setPlatformSmsNotifiedTime(new Date()); |
| | | orders.setUpdateTime(new Date()); |
| | | ordersMapper.updateById(orders); |
| | | // 6. 唤起微信支付 |
| | |
| | | // 取消/退款状态时查询退款记录 |
| | | Integer status = order.getStatus(); |
| | | if (status != null && (status == Constants.OrderStatus.overdue.getStatus() |
| | | || status == Constants.OrderStatus.closed.getStatus() |
| | | || status == Constants.OrderStatus.cancelOverdue.getStatus() |
| | | || status == Constants.OrderStatus.cancelling.getStatus() |
| | | || status == Constants.OrderStatus.cancelled.getStatus())) { |
| | | OrdersRefund ordersRefund = ordersRefundMapper.selectOne( |
| | | new QueryWrapper<OrdersRefund>().lambda() |
| | |
| | | |
| | | String optUserName = getCurrentUserName(); |
| | | |
| | | // 加急费日志(每次单独记录本次加急费) |
| | | Constants.OrderLogType urgentLogType = Constants.OrderLogType.urgent; |
| | | // 加急费日志 |
| | | OrderLog feeLog = new OrderLog(); |
| | | feeLog.setOrderId(order.getId()); |
| | | feeLog.setTitle(urgentLogType.getTitle()); |
| | | feeLog.setLogInfo(urgentLogType.getStatusInfo().replace("{param}", dto.getUrgentFee().toPlainString())); |
| | | feeLog.setObjType(urgentLogType.getStatus()); |
| | | feeLog.setTitle(Constants.OrderLogType.urgent.getTitle()); |
| | | feeLog.setLogInfo(Constants.OrderLogType.urgent.format(dto.getUrgentFee().toPlainString())); |
| | | feeLog.setObjType(Constants.OrderLogType.urgent.getStatus()); |
| | | feeLog.setOrderStatus(order.getStatus()); |
| | | feeLog.setOptUserType(3); |
| | | feeLog.setOptUserName(optUserName); |
| | |
| | | .eq(Orders::getId, order.getId()) |
| | | .set(Orders::getIsUrgent, Constants.ONE) |
| | | .set(Orders::getPlatformRewardAmount, urgentFeeFen) |
| | | .set(Orders::getPlatformSmsNotified, Constants.ZERO) // 重置通知状态为未通知 |
| | | .set(Orders::getPlatformSmsNotifiedTime, new Date()) // 重置通知基准时间为当前 |
| | | .set(Orders::getUpdateTime, new Date()); |
| | | |
| | | // 异地寄存且有取件门店时,生成司机核销码 |
| | |
| | | Member driver = memberMapper.selectById(dto.getDriverId()); |
| | | String driverName = driver != null ? driver.getName() : String.valueOf(dto.getDriverId()); |
| | | |
| | | Constants.OrderLogType dispatchLogType = Constants.OrderLogType.dispatch; |
| | | OrderLog driverLog = new OrderLog(); |
| | | driverLog.setOrderId(order.getId()); |
| | | driverLog.setTitle(dispatchLogType.getTitle()); |
| | | driverLog.setLogInfo(dispatchLogType.getStatusInfo().replace("{param}", driverName)); |
| | | driverLog.setObjType(dispatchLogType.getStatus()); |
| | | driverLog.setTitle(Constants.OrderLogType.assignDriver.getTitle()); |
| | | driverLog.setLogInfo(Constants.OrderLogType.assignDriver.format(driverName, dto.getUrgentFee().toPlainString())); |
| | | driverLog.setObjType(Constants.OrderLogType.assignDriver.getStatus()); |
| | | driverLog.setOrderStatus(order.getStatus()); |
| | | driverLog.setOptUserType(3); |
| | | driverLog.setOptUserName(optUserName); |
| | | driverLog.setCreateTime(new Date()); |
| | | driverLog.setDeleted(Constants.ZERO); |
| | | orderLogService.create(driverLog); |
| | | |
| | | // 短信通知指派司机(加急派单) |
| | | DriverInfo driverInfo = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda() |
| | | .eq(DriverInfo::getMemberId, dto.getDriverId()) |
| | | .eq(DriverInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (driverInfo != null) { |
| | | String address1 = order.getDepositShopAddress() != null ? order.getDepositShopAddress() : order.getDepositShopName(); |
| | | String address2 = order.getTakeShopAddress() != null ? order.getTakeShopAddress() : |
| | | (order.getTakeLocation() != null ? order.getTakeLocation() : ""); |
| | | // 配送费 = 司机配送费 + 加急费 |
| | | long totalDriverFee = (order.getDriverFee() != null ? order.getDriverFee() : 0L) + urgentFeeFen; |
| | | sendSmsNotify(driverInfo.getTelephone(), |
| | | Constants.SmsNotify.DRIVER_URGENT_DISPATCH, |
| | | "orderNo", order.getCode(), |
| | | "address1", address1, |
| | | "address2", address2, |
| | | "money1", String.valueOf(totalDriverFee / 100.0), |
| | | "money2", String.valueOf(urgentFeeFen / 100.0)); |
| | | } |
| | | } |
| | | |
| | | ordersMapper.update(updateWrapper); |
| | |
| | | .select("s1.link_phone", Orders::getDepositShopLinkPhone) |
| | | .select("s2.name", Orders::getTakeShopName) |
| | | .select("s2.address", Orders::getTakeShopAddress) |
| | | .select("s2.link_phone", Orders::getTakeShopLinkPhone) |
| | | .select("d.name", Orders::getDriverName) |
| | | .select("d.telephone", Orders::getDriverPhone) |
| | | .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID") |
| | | .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID") |
| | | .leftJoin("driver_info d on d.id = t.ACCEPT_DRIVER") |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .eq(Orders::getMemberId, memberId) |
| | | .eq(status != null, Orders::getStatus, status) |
| | |
| | | vo.setTakeShopId(o.getTakeShopId()); |
| | | vo.setTakeShopName(o.getTakeShopName()); |
| | | vo.setTakeShopAddress(o.getTakeShopAddress()); |
| | | vo.setTakeShopPhone(o.getTakeShopLinkPhone()); |
| | | } else { |
| | | vo.setTakeLocation(o.getTakeLocation()); |
| | | vo.setTakeLocationRemark(o.getTakeLocationRemark()); |
| | | } |
| | | |
| | | // 司机信息 |
| | | vo.setDriverName(o.getDriverName()); |
| | | vo.setDriverPhone(o.getDriverPhone()); |
| | | |
| | | // 取件联系人 |
| | | vo.setTakeUser(o.getTakeUser()); |
| | |
| | | // 物品明细 |
| | | vo.setDetailList(buildDetailList(details)); |
| | | |
| | | // 逾期信息(仅待取件状态计算) |
| | | if (Integer.valueOf(Constants.OrderStatus.arrived.getStatus()).equals(o.getStatus())) { |
| | | OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(o, details); |
| | | vo.setOverdue(overdueInfo.getOverdue()); |
| | | vo.setOverdueDays(overdueInfo.getOverdueDays()); |
| | | vo.setOverdueFee(overdueInfo.getOverdueFee()); |
| | | } |
| | | // 逾期状态 |
| | | fillOverdueStatus(vo, o, details); |
| | | voList.add(vo); |
| | | } |
| | | } |
| | |
| | | .select("s1.link_phone", Orders::getDepositShopLinkPhone) |
| | | .select("s2.name", Orders::getTakeShopName) |
| | | .select("s2.address", Orders::getTakeShopAddress) |
| | | .select("s2.link_phone", Orders::getTakeShopLinkPhone) |
| | | .select("d.name", Orders::getDriverName) |
| | | .select("d.telephone", Orders::getDriverPhone) |
| | | .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID") |
| | | .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID") |
| | | .eq(Orders::getPayStatus, Constants.ONE) |
| | | .and(w -> w.eq(Orders::getDepositShopId, shopId).or().eq(Orders::getTakeShopId, shopId)) |
| | | .eq(status != null, Orders::getStatus, status) |
| | | .in(statusList != null, Orders::getStatus, statusList) |
| | | .orderByDesc(Orders::getCreateTime); |
| | | .leftJoin("driver_info d on d.id = t.ACCEPT_DRIVER") |
| | | .eq(Orders::getPayStatus, Constants.ONE); |
| | | |
| | | // 门店待处理订单:按业务环节区分门店角色 |
| | | if (combinedStatus != null && Constants.equalsInteger(combinedStatus, Constants.SEVEN)) { |
| | | wrapper.and(w -> w |
| | | .and(w1 -> w1.eq(Orders::getDepositShopId, shopId) |
| | | .in(Orders::getStatus, Constants.OrderStatus.waitDeposit.getStatus(), |
| | | Constants.OrderStatus.deposited.getStatus())) |
| | | .or(w2 -> w2.eq(Orders::getTakeShopId, shopId) |
| | | .in(Orders::getStatus, Constants.OrderStatus.delivering.getStatus(), |
| | | Constants.OrderStatus.arrived.getStatus())) |
| | | ); |
| | | } else { |
| | | wrapper.and(w -> w.eq(Orders::getDepositShopId, shopId).or().eq(Orders::getTakeShopId, shopId)); |
| | | } |
| | | |
| | | wrapper.eq(status != null, Orders::getStatus, status) |
| | | .in(statusList != null && !Constants.equalsInteger(combinedStatus, Constants.SEVEN), Orders::getStatus, statusList) |
| | | .orderByDesc(Orders::getId); |
| | | |
| | | IPage<Orders> orderPage = ordersMapper.selectJoinPage(p, Orders.class, wrapper); |
| | | List<MyOrderVO> voList = new ArrayList<>(); |
| | |
| | | Constants.equalsInteger(o.getType(), Constants.ZERO)?o.getType():Objects.nonNull(o.getTakeShopId())?Constants.ONE:Constants.TWO) |
| | | ); |
| | | vo.setCreateTime(o.getCreateTime()); |
| | | vo.setRemark(o.getRemark()); |
| | | vo.setExpectedTakeTime(o.getExpectedTakeTime()); |
| | | |
| | | vo.setDepositShopName(o.getDepositShopName()); |
| | |
| | | if (o.getTakeShopId() != null) { |
| | | vo.setTakeShopName(o.getTakeShopName()); |
| | | vo.setTakeShopAddress(o.getTakeShopAddress()); |
| | | vo.setTakeShopPhone(o.getTakeShopLinkPhone()); |
| | | } else { |
| | | vo.setTakeLocation(o.getTakeLocation()); |
| | | vo.setTakeLocationRemark(o.getTakeLocationRemark()); |
| | | } |
| | | |
| | | // 司机信息 |
| | | vo.setDriverName(o.getDriverName()); |
| | | vo.setDriverPhone(o.getDriverPhone()); |
| | | |
| | | vo.setTakeUser(o.getTakeUser()); |
| | | vo.setTakePhone(o.getTakePhone()); |
| | |
| | | |
| | | vo.setDetailList(buildDetailList(details)); |
| | | |
| | | if (Integer.valueOf(Constants.OrderStatus.arrived.getStatus()).equals(o.getStatus())) { |
| | | OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(o, details); |
| | | vo.setOverdue(overdueInfo.getOverdue()); |
| | | vo.setOverdueDays(overdueInfo.getOverdueDays()); |
| | | vo.setOverdueFee(overdueInfo.getOverdueFee()); |
| | | } |
| | | |
| | | // 逾期状态 |
| | | fillOverdueStatus(vo, o, details); |
| | | |
| | | // if (Integer.valueOf(Constants.OrderStatus.arrived.getStatus()).equals(o.getStatus())) { |
| | | // OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(o, details); |
| | | // vo.setOverdue(overdueInfo.getOverdue()); |
| | | // vo.setOverdueDays(overdueInfo.getOverdueDays()); |
| | | // vo.setOverdueFee(overdueInfo.getOverdueFee()); |
| | | // } |
| | | voList.add(vo); |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | if (order == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在"); |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "核销码无效"); |
| | | } |
| | | return buildOrderDetailVO(order, false); |
| | | } |
| | |
| | | vo.setExpectedDepositTime(order.getExpectedDepositTime()); |
| | | vo.setExpectedTakeTime(order.getExpectedTakeTime()); |
| | | vo.setArriveTime(order.getArriveTime()); |
| | | vo.setStatusName(Constants.OrderStatus.getDescByKey(order.getStatus(),order.getType())); |
| | | |
| | | // 费用(分) |
| | | vo.setBasicAmount(order.getBasicAmount()); |
| | | vo.setDeclaredAmount(order.getDeclaredAmount()); |
| | | vo.setDeclaredFee(order.getDeclaredFee()); |
| | | vo.setUrgentAmount(order.getUrgentAmount()); |
| | | vo.setActualPayAmount(order.getPayAmount()); |
| | | vo.setIsUrgent(order.getIsUrgent()); |
| | | vo.setActualPayAmount(Constants.equalsInteger(order.getPayStatus(), Constants.ONE)?order.getPayAmount():order.getEstimatedAmount()); |
| | | |
| | | // 标记 |
| | | vo.setExceptionStatus(order.getExceptionStatus()); |
| | |
| | | |
| | | // 取件信息 |
| | | if (order.getTakeShopId() != null) { |
| | | vo.setTakeShopId(order.getTakeShopId()); |
| | | ShopInfo takeShop = shopInfoMapper.selectById(order.getTakeShopId()); |
| | | if (takeShop != null) { |
| | | vo.setTakeShopName(takeShop.getName()); |
| | |
| | | // 取件联系人 |
| | | vo.setTakeUser(order.getTakeUser()); |
| | | vo.setTakePhone(order.getTakePhone()); |
| | | |
| | | // 司机信息 |
| | | if (order.getAcceptDriver() != null) { |
| | | DriverInfo driver = driverInfoMapper.selectById(order.getAcceptDriver()); |
| | | if (driver != null) { |
| | | vo.setDriverId(driver.getId()); |
| | | vo.setDriverName(driver.getName()); |
| | | vo.setDriverPhone(driver.getTelephone()); |
| | | } |
| | | } |
| | | |
| | | // 物品类型名称 |
| | | if (order.getGoodType() != null) { |
| | |
| | | .eq(OrdersDetail::getDeleted, Constants.ZERO)); |
| | | vo.setDetailList(buildDetailList(details)); |
| | | |
| | | // 逾期信息 |
| | | OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(order, details); |
| | | vo.setOverdue(overdueInfo.getOverdue()); |
| | | vo.setOverdueDays(overdueInfo.getOverdueDays()); |
| | | vo.setOverdueFee(overdueInfo.getOverdueFee()); |
| | | // 逾期状态:0=未到店未逾期 1=未到店存在逾期 2=已到店未逾期 3=已到店待支付逾期 4=逾期已支付 |
| | | fillOverdueStatus(vo, order, details); |
| | | |
| | | // 退款信息(status=99取消时返回) |
| | | if (order.getStatus() != null && |
| | | Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.cancelled.getStatus())) { |
| | | vo.setRefundApplyTime(order.getCancelTime()); |
| | | OrdersRefund ordersRefund = ordersRefundMapper.selectOne( |
| | | new QueryWrapper<OrdersRefund>().lambda() |
| | | .eq(OrdersRefund::getOrderId, order.getId()) |
| | | .eq(OrdersRefund::getDeleted, Constants.ZERO) |
| | | .orderByDesc(OrdersRefund::getCreateTime) |
| | | .last("limit 1")); |
| | | vo.setRefundInfo(ordersRefund); |
| | | } |
| | | |
| | | // 核销码 |
| | | Integer status = order.getStatus(); |
| | |
| | | } else { |
| | | // 门店端:始终返回会员核销码 |
| | | vo.setMemberVerifyCode(order.getMemberVerifyCode()); |
| | | } |
| | | |
| | | // 异地寄存经纬度(就地寄存不返回) |
| | | if (Constants.ONE.equals(order.getType())) { |
| | | // status=3(已接单):返回存件门店经纬度 + 司机经纬度 |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.accepted.getStatus())) { |
| | | ShopInfo depositShop = shopInfoMapper.selectById(order.getDepositShopId()); |
| | | if (depositShop != null) { |
| | | vo.setDepositShopLng(depositShop.getLongitude()); |
| | | vo.setDepositShopLat(depositShop.getLatitude()); |
| | | } |
| | | if (order.getAcceptDriver() != null) { |
| | | DriverInfo driver = driverInfoMapper.selectById(order.getAcceptDriver()); |
| | | if (driver != null) { |
| | | vo.setDriverLng(driver.getLongitude()); |
| | | vo.setDriverLat(driver.getLatitude()); |
| | | } |
| | | } |
| | | } |
| | | // status=4(配送中):返回取件点经纬度 + 司机经纬度 |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.delivering.getStatus())) { |
| | | // 取件点经纬度(优先取件门店,否则订单上的取件坐标) |
| | | if (order.getTakeShopId() != null) { |
| | | ShopInfo takeShop = shopInfoMapper.selectById(order.getTakeShopId()); |
| | | if (takeShop != null) { |
| | | vo.setTakeLng(takeShop.getLongitude()); |
| | | vo.setTakeLat(takeShop.getLatitude()); |
| | | } |
| | | } else if (order.getTakeLgt() != null && order.getTakeLat() != null) { |
| | | vo.setTakeLng(order.getTakeLgt().doubleValue()); |
| | | vo.setTakeLat(order.getTakeLat().doubleValue()); |
| | | } |
| | | if (order.getAcceptDriver() != null) { |
| | | DriverInfo driver = driverInfoMapper.selectById(order.getAcceptDriver()); |
| | | if (driver != null) { |
| | | vo.setDriverLng(driver.getLongitude()); |
| | | vo.setDriverLat(driver.getLatitude()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 评价信息 |
| | | vo.setCommentStatus(order.getCommentStatus()); |
| | | if (Constants.equalsInteger(order.getCommentStatus(), Constants.ONE)) { |
| | | vo.setCommentTime(order.getCommentTime()); |
| | | // 查询评价记录,获取各对象评分 |
| | | List<OrderComment> comments = orderCommentMapper.selectList(new QueryWrapper<OrderComment>().lambda() |
| | | .eq(OrderComment::getOrderId, order.getId()) |
| | | .eq(OrderComment::getDeleted, Constants.ZERO)); |
| | | for (OrderComment c : comments) { |
| | | if (Constants.equalsInteger(c.getTargetType(), Constants.ONE)) { |
| | | vo.setDepositScore(c.getScore()); |
| | | vo.setCommentContent(c.getContent()); |
| | | } else if (Constants.equalsInteger(c.getTargetType(), Constants.TWO)) { |
| | | vo.setTakeScore(c.getScore()); |
| | | } else if (Constants.equalsInteger(c.getTargetType(), Constants.THREE)) { |
| | | vo.setDriverScore(c.getScore()); |
| | | } |
| | | } |
| | | // 评价附件图片 |
| | | vo.setCommentImages(getFileUrls(order.getId(), Constants.FileType.COMMENT_ATTACH.getKey(), imgPrefix)); |
| | | } |
| | | |
| | | return vo; |
| | |
| | | order.setStatus(Constants.OrderStatus.cancelled.getStatus()); |
| | | order.setCancelTime(now); |
| | | ordersMapper.updateById(order); |
| | | saveCancelLog(order, "会员取消订单(待支付)", reason, memberId); |
| | | saveCancelLog(order, Constants.OrderLogType.memberCancel, "会员取消订单(待支付)", memberId); |
| | | // 短信通知会员:订单已取消 |
| | | Member cancelMember1 = memberMapper.selectById(memberId); |
| | | sendSmsNotify(cancelMember1 != null ? cancelMember1.getTelephone() : null, |
| | | Constants.SmsNotify.MEMBER_CANCELLED, "orderNo", order.getCode()); |
| | | return; |
| | | } |
| | | |
| | | // 待寄存:直接取消,全额退款(不限订单类型) |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.waitDeposit.getStatus())) { |
| | | // 先标记订单已取消 |
| | | order.setStatus(Constants.OrderStatus.cancelled.getStatus()); |
| | | order.setCancelTime(now); |
| | | order.setRefundAmount(order.getPayAmount()); |
| | | ordersMapper.updateById(order); |
| | | |
| | | saveCancelLog(order, Constants.OrderLogType.memberCancel, "会员取消订单(待寄存,全额退款)", memberId); |
| | | // 通知会员:已取消 |
| | | sendOrderNotice(memberId, Constants.MemberOrderNotify.CANCELLED, orderId, |
| | | "orderNo", order.getCode()); |
| | | // 短信通知会员:订单已取消 |
| | | Member cancelMember2 = memberMapper.selectById(memberId); |
| | | sendSmsNotify(cancelMember2 != null ? cancelMember2.getTelephone() : null, |
| | | Constants.SmsNotify.MEMBER_CANCELLED, "orderNo", order.getCode()); |
| | | |
| | | // 调用微信退款V3,全额退款 |
| | | com.wechat.pay.java.service.refund.model.Refund refundResult; |
| | | try { |
| | | refundResult = wxPayV3Service.refund(order.getOutTradeNo(), order.getPayAmount(), order.getPayAmount(), |
| | | "订单退款", wxPayProperties.getV3RefundNotifyUrl()); |
| | | } catch (Exception e) { |
| | | log.error("待寄存订单退款调用异常, orderId={}", orderId, e); |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "退款失败,请稍后重试"); |
| | | } |
| | | |
| | | com.wechat.pay.java.service.refund.model.Status refundStatus = refundResult.getStatus(); |
| | | |
| | | // 记录退款信息 |
| | | OrdersRefund refund = new OrdersRefund(); |
| | | refund.setOrderId(orderId); |
| | |
| | | refund.setCancelInfo(reason); |
| | | refund.setCreateTime(now); |
| | | refund.setDeleted(Constants.ZERO); |
| | | |
| | | // 调用微信退款V3,全额退款 |
| | | Refund refundResult = wxPayV3Service.refund(order.getOutTradeNo(), order.getPayAmount(), order.getPayAmount(), |
| | | "订单退款", wxPayProperties.getV3RefundNotifyUrl()); |
| | | refund.setBeforeStatus(Constants.OrderStatus.waitDeposit.getStatus()); |
| | | refund.setRefundAmount(order.getPayAmount()); |
| | | refund.setRefundCode(refundResult.getOutRefundNo()); |
| | | refund.setStatus(Constants.ZERO); // 退款中 |
| | | |
| | | if (com.wechat.pay.java.service.refund.model.Status.SUCCESS.equals(refundStatus)) { |
| | | // 退款成功 |
| | | refund.setStatus(Constants.ONE); |
| | | } else if (com.wechat.pay.java.service.refund.model.Status.PROCESSING.equals(refundStatus)) { |
| | | // 退款中,等回调处理 |
| | | refund.setStatus(Constants.ZERO); |
| | | } else { |
| | | // 退款失败/异常(CLOSED / ABNORMAL / 其他) |
| | | log.error("待寄存订单退款失败, orderId={}, refundStatus={}", orderId, refundStatus); |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "退款失败,请联系客服处理"); |
| | | } |
| | | ordersRefundMapper.insert(refund); |
| | | |
| | | order.setStatus(Constants.OrderStatus.cancelled.getStatus()); |
| | | order.setCancelTime(now); |
| | | order.setRefundAmount(order.getPayAmount()); |
| | | ordersMapper.updateById(order); |
| | | |
| | | saveCancelLog(order, "会员取消订单(待寄存,全额退款)", reason, memberId); |
| | | // 通知会员:退款中 |
| | | sendOrderNotice(memberId, Constants.MemberOrderNotify.REFUNDING, orderId, |
| | | "orderNo", order.getCode()); |
| | | return; |
| | | } |
| | | |
| | |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅异地寄存订单可取消"); |
| | | } |
| | | |
| | | // 已寄存/已接单:进入取消中状态 |
| | | // 已寄存/已接单:直接将订单类型改为就地寄存 |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.deposited.getStatus()) |
| | | || Constants.equalsInteger(status, Constants.OrderStatus.accepted.getStatus())) { |
| | | order.setStatus(Constants.OrderStatus.cancelling.getStatus()); |
| | | order.setCancelTime(now); |
| | | ordersMapper.updateById(order); |
| | | saveCancelLog(order, "会员申请取消订单(已寄存/已接单)", reason, memberId); |
| | | // 通知存件门店:退款申请 |
| | | if (order.getDepositShopId() != null) { |
| | | sendShopNotice(order.getDepositShopId(), Constants.ShopOrderNotify.REFUNDING, orderId, |
| | | "orderNo", order.getCode()); |
| | | // 先保存原司机信息,用于后续通知 |
| | | Integer originalDriverId = order.getAcceptDriver(); |
| | | DriverInfo originalDriver = originalDriverId != null ? driverInfoMapper.selectById(originalDriverId) : null; |
| | | |
| | | ShopInfo depositShop = shopInfoMapper.selectById(order.getDepositShopId()); |
| | | // 取件点信息更新为存件门店,使用 UpdateWrapper 确保 null 字段也能生效 |
| | | UpdateWrapper<Orders> updateWrapper = new UpdateWrapper<>(); |
| | | updateWrapper.lambda() |
| | | .eq(Orders::getId, order.getId()) |
| | | .set(Orders::getType, Constants.ZERO) |
| | | .set(Orders::getTakeShopId, order.getDepositShopId()) |
| | | .set(Orders::getTakeShopName, order.getDepositShopName()) |
| | | .set(Orders::getTakeShopAddress, order.getDepositShopAddress()) |
| | | .set(Orders::getTakeShopLinkPhone, order.getDepositShopLinkPhone()) |
| | | .set(Orders::getTakeLocation, order.getDepositLocation()) |
| | | .set(Orders::getTakeLocationRemark, order.getDepositLocationRemark()) |
| | | .set(Orders::getTakeLat, order.getDepositLat()) |
| | | .set(Orders::getTakeLgt, order.getDepositLgt()) |
| | | .set(Orders::getExpectedTakeTime, new Date()); |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.accepted.getStatus())) { |
| | | updateWrapper.lambda() |
| | | .set(Orders::getAcceptDriver, null) |
| | | .set(Orders::getAcceptType, null) |
| | | .set(Orders::getAcceptTime, null); |
| | | } |
| | | // 通知司机:订单退款中(已接单情况下司机需停止服务) |
| | | if (order.getAcceptDriver() != null && Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.accepted.getStatus())) { |
| | | sendDriverNotice(order.getAcceptDriver(), Constants.DriverOrderNotify.REFUNDING, orderId, |
| | | ordersMapper.update(null, updateWrapper); |
| | | saveCancelLog(order, Constants.OrderLogType.memberCancelToConvert, "会员取消异地寄存订单,转为就地寄存", memberId); |
| | | // 通知司机:订单已取消(已接单情况下司机需停止服务) |
| | | if (originalDriverId != null && Constants.equalsInteger(status, Constants.OrderStatus.accepted.getStatus())) { |
| | | sendDriverNotice(originalDriverId, Constants.DriverOrderNotify.REFUNDING, orderId, |
| | | "orderNo", order.getCode()); |
| | | sendSmsNotify(originalDriver != null ? originalDriver.getTelephone() : null, |
| | | Constants.SmsNotify.DRIVER_REFUNDING, "orderNo", order.getCode()); |
| | | } |
| | | return; |
| | | } |
| | |
| | | /** |
| | | * 保存取消订单操作日志 |
| | | */ |
| | | private void saveCancelLog(Orders order, String title, String reason, Integer memberId) { |
| | | private void saveCancelLog(Orders order, Constants.OrderLogType logType, String reason, Integer memberId) { |
| | | OrderLog log = new OrderLog(); |
| | | log.setOrderId(order.getId()); |
| | | log.setTitle(title); |
| | | log.setLogInfo(reason); |
| | | log.setObjType(Constants.ORDER_LOG_CANCEL); |
| | | log.setTitle(logType.getTitle()); |
| | | log.setLogInfo(logType.format(reason)); |
| | | log.setObjType(logType.getStatus()); |
| | | log.setOrderStatus(order.getStatus()); |
| | | log.setOptUserId(memberId); |
| | | log.setOptUserType(0); // 0=用户 |
| | |
| | | /** |
| | | * 保存门店核销日志 |
| | | */ |
| | | private void saveShopVerifyLog(Orders order, String title, String logInfo, String remark, Integer shopId) { |
| | | private void saveShopVerifyLog(Orders order, Constants.OrderLogType logType, String logInfo, String remark, Integer shopId) { |
| | | OrderLog log = new OrderLog(); |
| | | log.setOrderId(order.getId()); |
| | | log.setTitle(title); |
| | | log.setLogInfo(logInfo); |
| | | log.setTitle(logType.getTitle()); |
| | | log.setLogInfo(logInfo != null ? logInfo : logType.getStatusInfo()); |
| | | log.setRemark(remark); |
| | | log.setObjType(logType.getStatus()); |
| | | log.setOrderStatus(order.getStatus()); |
| | | log.setOptUserId(shopId); |
| | | log.setOptUserType(2); // 2=门店 |
| | |
| | | sendShopNotice(order.getDepositShopId(), Constants.ShopOrderNotify.WAIT_VERIFY, order.getId(), |
| | | "orderNo", order.getCode()); |
| | | } |
| | | |
| | | // 短信通知存件门店:有新订单待核验 |
| | | if (order.getDepositShopId() != null) { |
| | | ShopInfo depositShop = shopInfoMapper.selectById(order.getDepositShopId()); |
| | | if (depositShop != null) { |
| | | sendSmsNotify(depositShop.getLinkPhone(), Constants.SmsNotify.SHOP_WAIT_VERIFY, |
| | | "orderNo", order.getCode()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (!Constants.equalsInteger(order.getMemberId(), memberId)) { |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "无权操作此订单"); |
| | | } |
| | | // 仅已完成(7)、已取消(99)、已退款(96)可删除 |
| | | // 仅已完成(7)、已取消(99) |
| | | int status = Constants.formatIntegerNum(order.getStatus()); |
| | | if (status != Constants.OrderStatus.finished.getStatus() |
| | | && status != Constants.OrderStatus.cancelled.getStatus() |
| | | && status != Constants.OrderStatus.closed.getStatus()) { |
| | | && status != Constants.OrderStatus.cancelled.getStatus()) { |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "当前订单状态不可删除"); |
| | | } |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | |
| | | } |
| | | shopInfo.setUpdateTime(now); |
| | | shopInfoMapper.updateById(shopInfo); |
| | | |
| | | // 短信通知门店:成功入驻 |
| | | String rawPassword = shopInfo.getTelephone() != null && shopInfo.getTelephone().length() >= 6 |
| | | ? shopInfo.getTelephone().substring(shopInfo.getTelephone().length() - 6) + "@123456" : ""; |
| | | sendSmsNotify(shopInfo.getTelephone(), |
| | | Constants.SmsNotify.SHOP_AUTH_SUCCESS, |
| | | "storeName", shopInfo.getName(), |
| | | "phone", shopInfo.getTelephone() != null ? shopInfo.getTelephone() : "", |
| | | "password", rawPassword); |
| | | |
| | | // 6. 押金支付完成后,若城市未开通则自动开通 |
| | | if (shopInfo.getAreaId() != null) { |
| | |
| | | orderCommentMapper.insert(driverComment); |
| | | } |
| | | |
| | | // 4.4 保存评价附件图片(obj_type=15,最多3张) |
| | | saveVerifyImages(order.getId(), dto.getImages(), Constants.FileType.COMMENT_ATTACH.getKey(), null); |
| | | |
| | | // 5. 更新门店/司机平均评分 |
| | | updateTargetScore(Constants.ONE, order.getDepositShopId()); |
| | | if (isRemote && order.getTakeShopId() != null) { |
| | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void verifyOrder(String verifyCode, Integer shopId, List<String> images, String remark) { |
| | | if (StringUtils.isBlank(verifyCode)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "核销码不能为空"); |
| | | } |
| | | // 先查会员核销码 |
| | | Orders query = new Orders(); |
| | | query.setMemberVerifyCode(verifyCode); |
| | | query.setDeleted(Constants.ZERO); |
| | | Orders byMemberCode = findOne(query); |
| | | if (byMemberCode != null) { |
| | | shopVerifyOrder(verifyCode, shopId, images, remark); |
| | | } else { |
| | | driverVerifyOrder(verifyCode, images, remark, shopId); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void verifyOrderByShopId(Integer orderId, Integer shopId, List<String> images, String remark) { |
| | | if (orderId == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单主键不能为空"); |
| | | } |
| | | // 根据订单主键查找订单 |
| | | Orders order = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getId, orderId) |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (order == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在"); |
| | | } |
| | | |
| | | // 查询门店名称用于日志 |
| | | String shopName = ""; |
| | | ShopInfo shopInfo = shopInfoMapper.selectById(shopId); |
| | | if (shopInfo != null) { |
| | | shopName = shopInfo.getName() != null ? shopInfo.getName() : ""; |
| | | } |
| | | |
| | | Integer status = order.getStatus(); |
| | | Date now = new Date(); |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.waitDeposit.getStatus())) { |
| | | // 待寄存(1) → 已寄存(2),两种类型通用 |
| | | // 校验当前门店是否为订单的存件门店 |
| | | if (!shopId.equals(order.getDepositShopId())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单不属于当前门店,无法核销"); |
| | | } |
| | | order.setStatus(Constants.equalsInteger(order.getType(),Constants.ZERO)?Constants.OrderStatus.arrived.getStatus():Constants.OrderStatus.deposited.getStatus()); |
| | | order.setDepositTime(now); |
| | | // 释放当前核销码,生成新的核销码供取件时使用 |
| | | String verifyCode = order.getMemberVerifyCode(); |
| | | if (StringUtils.isNotBlank(verifyCode)) { |
| | | releaseVerifyCode(verifyCode); |
| | | } |
| | | order.setMemberVerifyCode(generateVerifyCode()); |
| | | ordersMapper.updateById(order); |
| | | // 保存寄存图片(obj_type=2 订单寄存图片,最多3张) |
| | | saveVerifyImages(order.getId(), images, Constants.FileType.ORDER_DEPOSIT.getKey(), shopId); |
| | | // 记录订单日志 |
| | | saveShopVerifyLog(order, Constants.OrderLogType.shopDeposit, Constants.OrderLogType.shopDeposit.format(shopName), remark, shopId); |
| | | // 通知会员:门店核销成功 |
| | | if (Constants.equalsInteger(order.getType(), Constants.ONE)) { |
| | | // 异地寄存 → 待抢单 |
| | | sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.WAIT_GRAB, order.getId(), |
| | | "orderNo", order.getCode()); |
| | | } else { |
| | | // 就地寄存 → 待取件提醒 |
| | | sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.WAIT_PICKUP_REMIND, order.getId(), |
| | | "orderNo", order.getCode(), "shopName", shopName); |
| | | } |
| | | } else if (Constants.equalsInteger(status, Constants.OrderStatus.arrived.getStatus())) { |
| | | // 异地寄存 + 无取件门店 → 无法核销(客户自取,无门店操作) |
| | | if (Constants.equalsInteger(order.getType(), Constants.ONE) && order.getTakeShopId() == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单无取件门店,无法核销"); |
| | | } |
| | | // 校验取件门店与当前登录门店一致 |
| | | if (!shopId.equals(order.getTakeShopId())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单不属于当前门店,无法核销"); |
| | | } |
| | | // 校验是否已确认顾客到店 |
| | | if (order.getConfirmArriveTime() == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请先确认顾客到店"); |
| | | } |
| | | // 校验是否存在待处理的逾期费用 |
| | | if (Constants.equalsInteger(order.getOverdueStatus(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "存在逾期费用待处理,请先完成逾期费用支付"); |
| | | } |
| | | // 待取件(5) → 已完成(7) |
| | | order.setStatus(Constants.OrderStatus.finished.getStatus()); |
| | | order.setConfirmArriveTime(now); |
| | | ordersMapper.updateById(order); |
| | | // 订单完成,释放核销码 |
| | | String verifyCode = order.getMemberVerifyCode(); |
| | | if (StringUtils.isNotBlank(verifyCode)) { |
| | | releaseVerifyCode(verifyCode); |
| | | } |
| | | // 保存出库图片(obj_type=13 门店出库图片,最多3张) |
| | | saveVerifyImages(order.getId(), images, Constants.FileType.STORE_OUT.getKey(), shopId); |
| | | // 生成收益记录 |
| | | calculateAndSaveOrderFees(order.getId()); |
| | | generateRevenueRecords(order.getId()); |
| | | // 记录订单日志 |
| | | saveShopVerifyLog(order, Constants.OrderLogType.shopTake, Constants.OrderLogType.shopTake.format(shopName), remark, shopId); |
| | | // 通知会员:订单已完成 |
| | | sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.FINISHED, order.getId(), |
| | | "orderNo", order.getCode()); |
| | | // 通知存件门店和取件门店:订单已完成 |
| | | String settleDays = operationConfigBiz.getConfig().getSettlementDate(); |
| | | notifyBothShops(order, Constants.ShopOrderNotify.FINISHED, |
| | | "orderNo", order.getCode(), |
| | | "settleDays", settleDays != null ? settleDays : "7"); |
| | | // 通知司机:订单已完成 |
| | | if (order.getAcceptDriver() != null) { |
| | | sendDriverNotice(order.getAcceptDriver(), Constants.DriverOrderNotify.FINISHED, order.getId(), |
| | | "orderNo", order.getCode(), |
| | | "settleDays", settleDays != null ? settleDays : "7"); |
| | | } |
| | | } else { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不允许核销"); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void shopVerifyOrder(String verifyCode, Integer shopId, List<String> images, String remark) { |
| | | if (StringUtils.isBlank(verifyCode)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "核销码不能为空"); |
| | |
| | | // 保存寄存图片(obj_type=2 订单寄存图片,最多3张) |
| | | saveVerifyImages(order.getId(), images, Constants.FileType.ORDER_DEPOSIT.getKey(), shopId); |
| | | // 记录订单日志 |
| | | saveShopVerifyLog(order, "门店确认寄存", "门店【" + shopName + "】确认寄存", remark, shopId); |
| | | saveShopVerifyLog(order, Constants.OrderLogType.shopDeposit, Constants.OrderLogType.shopDeposit.format(shopName), remark, shopId); |
| | | // 通知会员:门店核销成功 |
| | | if (Constants.equalsInteger(order.getType(), Constants.ONE)) { |
| | | // 异地寄存 → 待抢单 |
| | |
| | | } else { |
| | | // 就地寄存 → 待取件提醒 |
| | | sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.WAIT_PICKUP_REMIND, order.getId(), |
| | | "orderNo", order.getCode()); |
| | | "orderNo", order.getCode(), "shopName", shopName); |
| | | } |
| | | } else if (Constants.equalsInteger(status, Constants.OrderStatus.arrived.getStatus())) { |
| | | // 异地寄存 + 无取件门店 → 无法核销(客户自取,无门店操作) |
| | |
| | | // 校验取件门店与当前登录门店一致 |
| | | if (!shopId.equals(order.getTakeShopId())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单不属于当前门店,无法核销"); |
| | | } |
| | | // 校验是否已确认顾客到店 |
| | | if (order.getConfirmArriveTime() == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请先确认顾客到店"); |
| | | } |
| | | // 校验是否存在待处理的逾期费用 |
| | | if (Constants.equalsInteger(order.getOverdueStatus(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "存在逾期费用待处理,请先完成逾期费用支付"); |
| | | } |
| | | // 待取件(5) → 已完成(7) |
| | | order.setStatus(Constants.OrderStatus.finished.getStatus()); |
| | |
| | | calculateAndSaveOrderFees(order.getId()); |
| | | generateRevenueRecords(order.getId()); |
| | | // 记录订单日志 |
| | | saveShopVerifyLog(order, "门店确认取件", "门店【" + shopName + "】确认取件,订单完成", remark, shopId); |
| | | saveShopVerifyLog(order, Constants.OrderLogType.shopTake, Constants.OrderLogType.shopTake.format(shopName), remark, shopId); |
| | | // 通知会员:订单已完成 |
| | | sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.FINISHED, order.getId(), |
| | | "orderNo", order.getCode()); |
| | |
| | | refundRecord.setType(3); // 出库退款 |
| | | refundRecord.setCreateTime(now); |
| | | refundRecord.setRefundRemark(remark); |
| | | refundRecord.setRefundAmount(order.getRefundAmount()); |
| | | refundRecord.setDeleted(Constants.ZERO); |
| | | refundRecord.setBeforeStatus(order.getStatus()); |
| | | ordersRefundMapper.insert(refundRecord); |
| | | |
| | | // 调用微信退款V3(放在最后,确保前置操作全部成功) |
| | |
| | | if (order.getRefundAmount() != null && order.getRefundAmount() > 0) { |
| | | logInfo += ",退款" + Constants.getFormatMoney(order.getRefundAmount()) + "元"; |
| | | } |
| | | saveShopVerifyLog(order, "门店确认出库", logInfo, remark, shopId); |
| | | saveShopVerifyLog(order, Constants.OrderLogType.shopOutStock, logInfo, remark, shopId); |
| | | // 通知会员:订单已完成 |
| | | sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.FINISHED, order.getId(), |
| | | "orderNo", order.getCode()); |
| | |
| | | Long takeShopFee = 0L; |
| | | Long driverFee = 0L; |
| | | |
| | | if (Constants.equalsInteger(order.getType(), Constants.TWO)) { |
| | | if (Constants.equalsInteger(order.getType(), Constants.ONE)) { |
| | | // 异地寄存:存件门店 + 司机 |
| | | driverFee = new BigDecimal(totalAmount) |
| | | .multiply(driverRate) |
| | |
| | | "orderNo", order.getCode(), |
| | | "destination", destination); |
| | | } |
| | | |
| | | // 短信通知会员:行李已送达 |
| | | Member arrivedMember = memberMapper.selectById(order.getMemberId()); |
| | | if (arrivedMember != null) { |
| | | sendSmsNotify(arrivedMember.getTelephone(), Constants.SmsNotify.MEMBER_ARRIVED, |
| | | "orderNo", order.getCode(), |
| | | "address", destination, |
| | | "code", order.getMemberVerifyCode() != null ? order.getMemberVerifyCode() : ""); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | ordersMapper.updateById(order); |
| | | |
| | | // 记录订单日志 |
| | | saveShopVerifyLog(order, "确认顾客到店(逾期)", |
| | | "门店【" + shopName + "】确认顾客到店,逾期" + overdueInfo.getOverdueDays() |
| | | + "天,逾期费用" + Constants.getFormatMoney(overdueInfo.getOverdueFee()) + "元", |
| | | String overdueLogInfo = "门店【" + shopName + "】确认顾客到店,逾期" + overdueInfo.getOverdueDays() |
| | | + "天,逾期费用" + Constants.getFormatMoney(overdueInfo.getOverdueFee()) + "元"; |
| | | saveShopVerifyLog(order, Constants.OrderLogType.shopConfirmArriveOverdue, overdueLogInfo, |
| | | null, shopId); |
| | | } else { |
| | | // 未逾期:标记逾期状态为0,订单保持当前状态 |
| | |
| | | if (order.getRefundAmount() != null && order.getRefundAmount() > 0) { |
| | | logInfo += ",需退款" + Constants.getFormatMoney(order.getRefundAmount()) + "元"; |
| | | } |
| | | saveShopVerifyLog(order, "确认顾客到店", logInfo, null, shopId); |
| | | saveShopVerifyLog(order, Constants.OrderLogType.shopConfirmArrive, logInfo, null, shopId); |
| | | } |
| | | } |
| | | |
| | |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.cancelled.getStatus())) { |
| | | return "订单已取消,感谢您的支持,欢迎下次再会!"; |
| | | } |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.cancelling.getStatus())) { |
| | | return "退款申请已提交,平台会尽快为您处理退款"; |
| | | } |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.closed.getStatus())) { |
| | | return "退款已成功原路返回,请注意查收"; |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | /** |
| | | * 填充逾期状态到 VO(MyOrderVO) |
| | | * overdueStatus: 0=未到店未逾期 1=未到店存在逾期 2=已到店未逾期 3=已到店待支付逾期 4=逾期已支付 |
| | | */ |
| | | private void fillOverdueStatus(MyOrderVO vo, Orders order, List<OrdersDetail> details) { |
| | | Integer[] result = calcOverdueStatus(order, details); |
| | | vo.setOverdueStatus(result[0]); |
| | | vo.setOverdue(result[1] == 1); |
| | | vo.setOverdueDays(result[2]); |
| | | vo.setOverdueFee(result[3].longValue()); |
| | | } |
| | | |
| | | /** |
| | | * 填充逾期状态到 VO(MyOrderDetailVO) |
| | | */ |
| | | private void fillOverdueStatus(MyOrderDetailVO vo, Orders order, List<OrdersDetail> details) { |
| | | Integer[] result = calcOverdueStatus(order, details); |
| | | vo.setOverdueStatus(result[0]); |
| | | vo.setOverdue(result[1] == 1); |
| | | vo.setOverdueDays(result[2]); |
| | | vo.setOverdueFee(result[3].longValue()); |
| | | } |
| | | |
| | | /** |
| | | * 计算逾期状态 |
| | | * @return [overdueStatus, isOverdue(0/1), overdueDays, overdueFee] |
| | | */ |
| | | private Integer[] calcOverdueStatus(Orders order, List<OrdersDetail> details) { |
| | | // 4=逾期已支付(订单 overdueStatus=2) |
| | | if (Constants.equalsInteger(order.getOverdueStatus(), Constants.TWO)) { |
| | | return new Integer[]{4, 1, order.getOverdueDays(), order.getOverdueAmount() != null ? order.getOverdueAmount().intValue() : 0}; |
| | | } |
| | | // 3=已到店待支付逾期(订单 overdueStatus=1) |
| | | if (Constants.equalsInteger(order.getOverdueStatus(), Constants.ONE)) { |
| | | return new Integer[]{3, 1, order.getOverdueDays(), order.getOverdueAmount() != null ? order.getOverdueAmount().intValue() : 0}; |
| | | } |
| | | // 计算实时逾期 |
| | | OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(order, details); |
| | | boolean hasOverdue = overdueInfo.getOverdue() != null && overdueInfo.getOverdue() |
| | | && overdueInfo.getOverdueFee() != null && overdueInfo.getOverdueFee() > 0; |
| | | if (order.getConfirmArriveTime() != null) { |
| | | // 已到店 |
| | | int days = hasOverdue ? overdueInfo.getOverdueDays() : 0; |
| | | long fee = hasOverdue ? overdueInfo.getOverdueFee() : 0L; |
| | | return new Integer[]{2, hasOverdue ? 1 : 0, days, (int) fee}; |
| | | } else { |
| | | // 未到店 |
| | | if (hasOverdue) { |
| | | return new Integer[]{1, 1, overdueInfo.getOverdueDays(), overdueInfo.getOverdueFee().intValue()}; |
| | | } else { |
| | | return new Integer[]{0, 0, 0, 0}; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 逾期费用内部计算(不查库,接受预查询的数据) |
| | | * 供分页等已查询明细的业务场景复用,避免重复查询 |
| | | */ |
| | |
| | | // 物品基础日费用 = Σ(单价 × 数量) |
| | | long dailyBaseFee = 0L; |
| | | for (OrdersDetail d : details) { |
| | | dailyBaseFee += (d.getUnitPrice() != null ? d.getUnitPrice() : 0L) |
| | | * (d.getNum() != null ? d.getNum() : 0); |
| | | dailyBaseFee += (d.getLocallyPrice() != null ? d.getLocallyPrice() : 0L) |
| | | * (d.getNum() != null ? d.getNum() : 1); |
| | | } |
| | | |
| | | Date now = new Date(); |
| | |
| | | |
| | | /** |
| | | * 就地寄存逾期天数计算 |
| | | * 过了预计取件时间当天的12点后才算一天 |
| | | * 过了预计取件日期的次日(只比较年月日)后开始计逾期天数 |
| | | */ |
| | | private int calcLocalOverdueDays(Date now, Date expectedTakeTime) { |
| | | if (expectedTakeTime == null || !now.after(expectedTakeTime)) { |
| | | if (expectedTakeTime == null) { |
| | | return 0; |
| | | } |
| | | // 基准时间 = 预计取件日期的12:00 |
| | | // 只取年月日 |
| | | Calendar baseCal = Calendar.getInstance(); |
| | | baseCal.setTime(expectedTakeTime); |
| | | baseCal.set(Calendar.HOUR_OF_DAY, 12); |
| | | baseCal.set(Calendar.HOUR_OF_DAY, 0); |
| | | baseCal.set(Calendar.MINUTE, 0); |
| | | baseCal.set(Calendar.SECOND, 0); |
| | | baseCal.set(Calendar.MILLISECOND, 0); |
| | | Date baseTime = baseCal.getTime(); |
| | | |
| | | if (!now.after(baseTime)) { |
| | | return 0; |
| | | } |
| | | // 逾期天数 = 当前日期 - 基准日期(按天取差) |
| | | Calendar nowCal = Calendar.getInstance(); |
| | | nowCal.setTime(now); |
| | | nowCal.set(Calendar.HOUR_OF_DAY, 0); |
| | |
| | | nowCal.set(Calendar.SECOND, 0); |
| | | nowCal.set(Calendar.MILLISECOND, 0); |
| | | |
| | | Calendar baseDateCal = Calendar.getInstance(); |
| | | baseDateCal.setTime(baseTime); |
| | | baseDateCal.set(Calendar.HOUR_OF_DAY, 0); |
| | | baseDateCal.set(Calendar.MINUTE, 0); |
| | | baseDateCal.set(Calendar.SECOND, 0); |
| | | baseDateCal.set(Calendar.MILLISECOND, 0); |
| | | |
| | | long diffMs = nowCal.getTimeInMillis() - baseDateCal.getTimeInMillis(); |
| | | int days = (int) (diffMs / (1000 * 60 * 60 * 24)); |
| | | return Math.max(days, 0); |
| | | // 基准日期 = 预计取件日期的次日,当天及之前不算逾期 |
| | | if (nowCal.before(baseCal)) { |
| | | return 0; |
| | | } |
| | | // 逾期天数 = 当前日期 - 基准日期 |
| | | long diffMs = nowCal.getTimeInMillis() - baseCal.getTimeInMillis(); |
| | | return (int) (diffMs / (1000 * 60 * 60 * 24)); |
| | | } |
| | | |
| | | /** |
| | | * 异地寄存逾期天数计算 |
| | | * 过了转移到店时间当天的晚上12点(24:00)后才算第一天 |
| | | * 过了转移到店日期的次日(只比较年月日)后开始计逾期天数 |
| | | */ |
| | | private int calcRemoteOverdueDays(Date now, Date arriveTime) { |
| | | if (arriveTime == null || !now.after(arriveTime)) { |
| | | if (arriveTime == null) { |
| | | return 0; |
| | | } |
| | | // 基准时间 = 转移到店日期的次日 00:00(即当天24:00) |
| | | // 只取年月日 |
| | | Calendar baseCal = Calendar.getInstance(); |
| | | baseCal.setTime(arriveTime); |
| | | baseCal.set(Calendar.HOUR_OF_DAY, 0); |
| | | baseCal.set(Calendar.MINUTE, 0); |
| | | baseCal.set(Calendar.SECOND, 0); |
| | | baseCal.set(Calendar.MILLISECOND, 0); |
| | | baseCal.add(Calendar.DAY_OF_MONTH, 1); // 次日00:00 = 当天24:00 |
| | | Date baseTime = baseCal.getTime(); |
| | | |
| | | if (!now.after(baseTime)) { |
| | | return 0; |
| | | } |
| | | // 逾期天数 = 当前日期 - 基准日期 |
| | | Calendar nowCal = Calendar.getInstance(); |
| | | nowCal.setTime(now); |
| | | nowCal.set(Calendar.HOUR_OF_DAY, 0); |
| | |
| | | nowCal.set(Calendar.SECOND, 0); |
| | | nowCal.set(Calendar.MILLISECOND, 0); |
| | | |
| | | Calendar baseDateCal = Calendar.getInstance(); |
| | | baseDateCal.setTime(baseTime); |
| | | baseDateCal.set(Calendar.HOUR_OF_DAY, 0); |
| | | baseDateCal.set(Calendar.MINUTE, 0); |
| | | baseDateCal.set(Calendar.SECOND, 0); |
| | | baseDateCal.set(Calendar.MILLISECOND, 0); |
| | | |
| | | long diffMs = nowCal.getTimeInMillis() - baseDateCal.getTimeInMillis(); |
| | | int days = (int) (diffMs / (1000 * 60 * 60 * 24)); |
| | | return Math.max(days, 0); |
| | | // 基准日期 = 到店日期的次日,当天及之前不算逾期 |
| | | baseCal.add(Calendar.DAY_OF_MONTH, 1); |
| | | if (nowCal.before(baseCal)) { |
| | | return 0; |
| | | } |
| | | // 逾期天数 = 当前日期 - 基准日期 |
| | | long diffMs = nowCal.getTimeInMillis() - baseCal.getTimeInMillis(); |
| | | return (int) (diffMs / (1000 * 60 * 60 * 24)); |
| | | } |
| | | |
| | | @Override |
| | |
| | | ActiveOrderTipVO vo = new ActiveOrderTipVO(); |
| | | vo.setOrderId(order.getId()); |
| | | vo.setStatus(order.getStatus()); |
| | | vo.setStatusDesc(Constants.OrderStatus.getDescByKey(order.getStatus(), order.getType())); |
| | | |
| | | // 构建提示文案 |
| | | boolean isLocal = Constants.equalsInteger(order.getType(), Constants.ZERO); |
| | |
| | | return vo; |
| | | } |
| | | |
| | | @Override |
| | | public int cancelTimeoutUnpaidOrders() { |
| | | // 获取超时配置(分钟) |
| | | String autoCancelTimeStr = operationConfigBiz.getConfig().getAutoCancelTime(); |
| | | if (StringUtils.isBlank(autoCancelTimeStr)) { |
| | | log.info("未配置超时取消时间,跳过"); |
| | | return 0; |
| | | } |
| | | int autoCancelMinutes; |
| | | try { |
| | | autoCancelMinutes = Integer.parseInt(autoCancelTimeStr); |
| | | } catch (NumberFormatException e) { |
| | | log.warn("超时取消时间配置异常: {}", autoCancelTimeStr); |
| | | return 0; |
| | | } |
| | | if (autoCancelMinutes <= 0) { |
| | | return 0; |
| | | } |
| | | |
| | | // 查询所有超时未支付订单:status=0 且 创建时间 + 配置分钟数 < 当前时间 |
| | | Date deadline = new Date(System.currentTimeMillis() - (long) autoCancelMinutes * 60 * 1000); |
| | | List<Orders> timeoutOrders = ordersMapper.selectList(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getStatus, Constants.OrderStatus.waitPay.getStatus()) |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .lt(Orders::getCreateTime, deadline)); |
| | | |
| | | if (timeoutOrders == null || timeoutOrders.isEmpty()) { |
| | | return 0; |
| | | } |
| | | |
| | | int count = 0; |
| | | Date now = new Date(); |
| | | for (Orders order : timeoutOrders) { |
| | | try { |
| | | order.setStatus(Constants.OrderStatus.cancelled.getStatus()); |
| | | order.setCancelTime(now); |
| | | order.setUpdateTime(now); |
| | | ordersMapper.updateById(order); |
| | | |
| | | // 写入操作日志 |
| | | OrderLog orderLog = new OrderLog(); |
| | | orderLog.setOrderId(order.getId()); |
| | | orderLog.setTitle(Constants.OrderLogType.systemCancel.getTitle()); |
| | | orderLog.setLogInfo(Constants.OrderLogType.systemCancel.format("订单超时" + autoCancelMinutes + "分钟未支付,系统自动取消")); |
| | | orderLog.setObjType(Constants.OrderLogType.systemCancel.getStatus()); |
| | | orderLog.setOrderStatus(Constants.OrderStatus.cancelled.getStatus()); |
| | | orderLog.setOptUserType(3); // 3=系统 |
| | | orderLog.setCreateTime(now); |
| | | orderLog.setDeleted(Constants.ZERO); |
| | | orderLogService.create(orderLog); |
| | | |
| | | // 短信通知会员:订单已取消 |
| | | if (order.getMemberId() != null) { |
| | | Member member = memberMapper.selectById(order.getMemberId()); |
| | | sendSmsNotify(member != null ? member.getTelephone() : null, |
| | | Constants.SmsNotify.MEMBER_CANCELLED, "orderNo", order.getCode()); |
| | | } |
| | | |
| | | count++; |
| | | } catch (Exception e) { |
| | | log.error("取消超时订单异常, orderId={}, error={}", order.getId(), e.getMessage()); |
| | | } |
| | | } |
| | | log.info("超时未支付订单自动取消完成,共取消{}单", count); |
| | | return count; |
| | | } |
| | | |
| | | @Override |
| | | public int notifyUngrabbedOrders() { |
| | | // 获取无人抢单通知时间配置(分钟) |
| | | String noGrabTimeStr = operationConfigBiz.getConfig().getNoGrabNotifyTime(); |
| | | if (StringUtils.isBlank(noGrabTimeStr)) { |
| | | return 0; |
| | | } |
| | | int noGrabMinutes; |
| | | try { |
| | | noGrabMinutes = Integer.parseInt(noGrabTimeStr); |
| | | } catch (NumberFormatException e) { |
| | | log.warn("无人抢单通知时间配置异常: {}", noGrabTimeStr); |
| | | return 0; |
| | | } |
| | | if (noGrabMinutes <= 0) { |
| | | return 0; |
| | | } |
| | | |
| | | // 获取通知人员主键列表 |
| | | String noGrabUsers = operationConfigBiz.getConfig().getNoGrabNotifyUsers(); |
| | | if (StringUtils.isBlank(noGrabUsers)) { |
| | | return 0; |
| | | } |
| | | List<String> userIdStrList = Arrays.asList(noGrabUsers.split(",")); |
| | | List<Integer> userIds = new ArrayList<>(); |
| | | for (String idStr : userIdStrList) { |
| | | if (StringUtils.isNotBlank(idStr.trim())) { |
| | | userIds.add(Integer.parseInt(idStr.trim())); |
| | | } |
| | | } |
| | | if (userIds.isEmpty()) { |
| | | return 0; |
| | | } |
| | | |
| | | // 查询通知人员手机号 |
| | | List<String> notifyPhones = new ArrayList<>(); |
| | | for (Integer userId : userIds) { |
| | | SystemUser user = systemUserMapper.selectById(userId); |
| | | if (user != null && StringUtils.isNotBlank(user.getMobile())) { |
| | | notifyPhones.add(user.getMobile()); |
| | | } |
| | | } |
| | | if (notifyPhones.isEmpty()) { |
| | | log.warn("无人抢单通知人员均无有效手机号"); |
| | | return 0; |
| | | } |
| | | |
| | | // 查询异地已寄存(status=2)、未通知(platformSmsNotified=0或null)、超时的订单 |
| | | Date deadline = new Date(System.currentTimeMillis() - (long) noGrabMinutes * 60 * 1000); |
| | | List<Orders> ungrabbedOrders = ordersMapper.selectList(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getType, Constants.ONE) // 异地寄存 |
| | | .eq(Orders::getStatus, Constants.OrderStatus.deposited.getStatus()) // 已寄存 |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .ne(Orders::getPlatformSmsNotified, Constants.ONE) // 未通知 |
| | | .lt(Orders::getPlatformSmsNotifiedTime, deadline)); // 通知基准时间超过配置时间 |
| | | |
| | | if (ungrabbedOrders == null || ungrabbedOrders.isEmpty()) { |
| | | return 0; |
| | | } |
| | | |
| | | int count = 0; |
| | | Date now = new Date(); |
| | | for (Orders order : ungrabbedOrders) { |
| | | try { |
| | | // 给所有通知人员发短信 |
| | | for (String phone : notifyPhones) { |
| | | sendSmsNotify(phone, Constants.SmsNotify.PLATFORM_WAIT_GRAB, |
| | | "orderNo", order.getCode(), |
| | | "time", String.valueOf(noGrabMinutes)); |
| | | } |
| | | // 标记已通知 + 记录通知时间 |
| | | order.setPlatformSmsNotified(Constants.ONE); |
| | | order.setPlatformSmsNotifiedTime(now); |
| | | order.setUpdateTime(now); |
| | | ordersMapper.updateById(order); |
| | | count++; |
| | | } catch (Exception e) { |
| | | log.error("无人抢单短信通知异常, orderId={}, error={}", order.getId(), e.getMessage()); |
| | | } |
| | | } |
| | | log.info("无人抢单短信通知完成,共通知{}单", count); |
| | | return count; |
| | | } |
| | | |
| | | @Override |
| | | public int autoCompleteOrders() { |
| | | // 获取自动确认收货天数配置 |
| | | String autoConfirmDaysStr = operationConfigBiz.getConfig().getAutoConfirmReceipt(); |
| | | if (StringUtils.isBlank(autoConfirmDaysStr)) { |
| | | return 0; |
| | | } |
| | | int autoConfirmDays; |
| | | try { |
| | | autoConfirmDays = Integer.parseInt(autoConfirmDaysStr); |
| | | } catch (NumberFormatException e) { |
| | | log.warn("自动确认收货天数配置异常: {}", autoConfirmDaysStr); |
| | | return 0; |
| | | } |
| | | if (autoConfirmDays <= 0) { |
| | | return 0; |
| | | } |
| | | |
| | | // 查询已送达(status=5)且送达时间超过配置天数的订单 |
| | | Date deadline = new Date(System.currentTimeMillis() - (long) autoConfirmDays * 24 * 60 * 60 * 1000); |
| | | List<Orders> orders = ordersMapper.selectList(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getStatus, Constants.OrderStatus.arrived.getStatus()) |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .isNotNull(Orders::getArriveTime) |
| | | .lt(Orders::getArriveTime, deadline)); |
| | | |
| | | if (orders == null || orders.isEmpty()) { |
| | | return 0; |
| | | } |
| | | |
| | | int count = 0; |
| | | Date now = new Date(); |
| | | for (Orders order : orders) { |
| | | try { |
| | | // 逾期未支付的不自动完成 |
| | | if (Constants.equalsInteger(order.getOverdueStatus(), Constants.ONE)) { |
| | | continue; |
| | | } |
| | | |
| | | // 更新订单状态为已完成 |
| | | order.setStatus(Constants.OrderStatus.finished.getStatus()); |
| | | order.setFinishTime(now); |
| | | order.setUpdateTime(now); |
| | | ordersMapper.updateById(order); |
| | | |
| | | // 释放核销码 |
| | | if (StringUtils.isNotBlank(order.getMemberVerifyCode())) { |
| | | releaseVerifyCode(order.getMemberVerifyCode()); |
| | | } |
| | | |
| | | // 生成收益记录 |
| | | calculateAndSaveOrderFees(order.getId()); |
| | | generateRevenueRecords(order.getId()); |
| | | |
| | | // 记录操作日志 |
| | | OrderLog orderLog = new OrderLog(); |
| | | orderLog.setOrderId(order.getId()); |
| | | orderLog.setTitle(Constants.OrderLogType.systemComplete.getTitle()); |
| | | orderLog.setLogInfo(Constants.OrderLogType.systemComplete.format("订单已送达超过" + autoConfirmDays + "天未确认,系统自动完成")); |
| | | orderLog.setObjType(Constants.OrderLogType.systemComplete.getStatus()); |
| | | orderLog.setOrderStatus(Constants.OrderStatus.finished.getStatus()); |
| | | orderLog.setOptUserType(3); // 3=系统 |
| | | orderLog.setCreateTime(now); |
| | | orderLog.setDeleted(Constants.ZERO); |
| | | orderLogService.create(orderLog); |
| | | |
| | | // 通知会员:订单已完成 |
| | | sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.FINISHED, order.getId(), |
| | | "orderNo", order.getCode()); |
| | | // 通知存件门店和取件门店 |
| | | String settleDays = operationConfigBiz.getConfig().getSettlementDate(); |
| | | notifyBothShops(order, Constants.ShopOrderNotify.FINISHED, |
| | | "orderNo", order.getCode(), |
| | | "settleDays", settleDays != null ? settleDays : "7"); |
| | | // 通知司机 |
| | | if (order.getAcceptDriver() != null) { |
| | | sendDriverNotice(order.getAcceptDriver(), Constants.DriverOrderNotify.FINISHED, order.getId(), |
| | | "orderNo", order.getCode(), |
| | | "settleDays", settleDays != null ? settleDays : "7"); |
| | | } |
| | | |
| | | count++; |
| | | } catch (Exception e) { |
| | | log.error("自动完成订单异常, orderId={}, error={}", order.getId(), e.getMessage()); |
| | | } |
| | | } |
| | | log.info("自动完成超时订单完成,共完成{}单", count); |
| | | return count; |
| | | } |
| | | |
| | | /** |
| | | * 发送短信通知(失败不影响主业务) |
| | | * @param phone 接收手机号 |
| | | * @param smsNotify 短信模板枚举 |
| | | * @param paramPairs 模板参数,key-value 交替传入,如 "orderNo", "XL202604220001" |
| | | */ |
| | | private void sendSmsNotify(String phone, Constants.SmsNotify smsNotify, String... paramPairs) { |
| | | if (StringUtils.isBlank(phone)) { |
| | | return; |
| | | } |
| | | String content = smsNotify.format(paramPairs); |
| | | try { |
| | | JSONObject templateParam = new JSONObject(); |
| | | for (int i = 0; i < paramPairs.length - 1; i += 2) { |
| | | templateParam.put(paramPairs[i], paramPairs[i + 1]); |
| | | } |
| | | boolean result = AliSmsService.sendSms(phone, smsNotify.getTemplateCode(), |
| | | templateParam.toJSONString()); |
| | | if (result) { |
| | | log.info("短信发送成功: phone={}, template={}", phone, smsNotify.name()); |
| | | } else { |
| | | log.warn("短信发送失败: phone={}, template={}", phone, smsNotify.name()); |
| | | } |
| | | // 存储短信记录 |
| | | Smsrecord record = new Smsrecord(); |
| | | record.setPhone(phone); |
| | | record.setContent(content); |
| | | record.setType(Constants.ONE); // 1=订单通知 |
| | | record.setStatus(result ? Constants.ONE : Constants.ZERO); // 1=已发送, 0=发送失败 |
| | | record.setCreateTime(new Date()); |
| | | record.setDeleted(Constants.ZERO); |
| | | smsrecordMapper.insert(record); |
| | | } catch (Exception e) { |
| | | log.error("短信发送异常: phone={}, template={}, error={}", phone, smsNotify.name(), e.getMessage()); |
| | | // 异常也记录 |
| | | try { |
| | | Smsrecord record = new Smsrecord(); |
| | | record.setPhone(phone); |
| | | record.setContent(content); |
| | | record.setType(Constants.ONE); |
| | | record.setStatus(Constants.ZERO); // 发送失败 |
| | | record.setCreateTime(new Date()); |
| | | record.setDeleted(Constants.ZERO); |
| | | smsrecordMapper.insert(record); |
| | | } catch (Exception ignored) {} |
| | | } |
| | | } |
| | | |
| | | } |