| | |
| | | package com.doumee.service.business.impl; |
| | | |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.doumee.biz.system.AreasBiz; |
| | | import com.doumee.biz.system.OperationConfigBiz; |
| | | import com.doumee.biz.system.SystemDictDataBiz; |
| | | import com.doumee.config.wx.SendWxMessage; |
| | | import com.doumee.config.wx.WxMiniConfig; |
| | | import com.doumee.config.wx.WxMiniUtilService; |
| | | import com.doumee.core.constants.Constants; |
| | | import com.doumee.core.constants.ResponseStatus; |
| | | import com.doumee.core.exception.BusinessException; |
| | | import com.doumee.core.model.LoginUserInfo; |
| | | import com.doumee.core.model.PageData; |
| | | import com.doumee.core.model.PageWrap; |
| | | import com.doumee.core.utils.DateUtil; |
| | | import com.doumee.core.utils.GeoUtils; |
| | | import com.doumee.core.utils.Tencent.MapUtil; |
| | | import com.doumee.core.utils.Utils; |
| | | import com.doumee.dao.business.*; |
| | | import com.doumee.dao.business.model.*; |
| | | import com.doumee.dao.dto.*; |
| | | import com.doumee.dao.vo.OrderReleaseVO; |
| | | import com.doumee.dao.vo.PayResponse; |
| | | import com.doumee.service.business.AliSmsService; |
| | | import com.doumee.dao.system.SystemUserMapper; |
| | | import com.doumee.dao.system.model.SystemDictData; |
| | | import com.doumee.dao.system.model.SystemUser; |
| | | import com.doumee.dao.dto.CalculateLocalPriceDTO; |
| | | import com.doumee.dao.dto.CalculateRemotePriceDTO; |
| | | import com.doumee.dao.dto.CommentOrderDTO; |
| | | import com.doumee.dao.dto.CreateOrderDTO; |
| | | import com.doumee.dao.dto.DispatchDTO; |
| | | import com.doumee.dao.dto.MyOrderDTO; |
| | | import com.doumee.dao.dto.OrderItemDTO; |
| | | import com.doumee.dao.vo.*; |
| | | import com.doumee.service.business.OrderLogService; |
| | | import com.doumee.service.business.OrdersService; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.doumee.service.business.AreasService; |
| | | import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest; |
| | | import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; |
| | | import com.github.binarywang.wxpay.exception.WxPayException; |
| | | import com.github.xiaoymin.knife4j.core.util.CollectionUtils; |
| | | import com.github.yulichang.wrapper.MPJLambdaWrapper; |
| | | import com.wechat.pay.java.service.partnerpayments.jsapi.model.Amount; |
| | | import com.wechat.pay.java.service.partnerpayments.jsapi.model.Payer; |
| | | import com.wechat.pay.java.service.partnerpayments.jsapi.model.PrepayRequest; |
| | | import com.wechat.pay.java.service.partnerpayments.jsapi.model.PrepayWithRequestPaymentResponse; |
| | | import com.wechat.pay.java.service.refund.model.RefundNotification; |
| | | import jodd.util.StringUtil; |
| | | import lombok.With; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import nonapi.io.github.classgraph.json.Id; |
| | | import org.apache.poi.sl.image.ImageHeaderEMF; |
| | | import org.checkerframework.checker.units.qual.A; |
| | | import org.springframework.beans.BeanUtils; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.redis.core.RedisTemplate; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.util.StringUtils; |
| | | import org.springframework.web.context.request.RequestContextHolder; |
| | | import org.springframework.web.context.request.ServletRequestAttributes; |
| | | |
| | | import javax.annotation.Resource; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 订单信息记录Service实现 |
| | | * @author 江蹄蹄 |
| | | * @date 2025/07/09 12:00 |
| | | * 寄存订单信息Service实现 |
| | | * @author rk |
| | | * @date 2026/04/10 |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class OrdersServiceImpl implements OrdersService { |
| | | |
| | |
| | | private OrdersMapper ordersMapper; |
| | | |
| | | @Autowired |
| | | private SystemDictDataBiz systemDictDataBiz; |
| | | private MemberMapper memberMapper; |
| | | |
| | | @Autowired |
| | | private ShopInfoMapper shopInfoMapper; |
| | | |
| | | @Autowired |
| | | private DriverInfoMapper driverInfoMapper; |
| | | |
| | | @Autowired |
| | | private CategoryMapper categoryMapper; |
| | |
| | | private MultifileMapper multifileMapper; |
| | | |
| | | @Autowired |
| | | private OrderLogMapper orderLogMapper; |
| | | private OrdersDetailMapper ordersDetailMapper; |
| | | |
| | | @Autowired |
| | | private MemberMapper memberMapper; |
| | | private SystemDictDataBiz systemDictDataBiz; |
| | | |
| | | @Autowired |
| | | private MemberRevenueMapper memberRevenueMapper; |
| | | private OrderLogService orderLogService; |
| | | |
| | | @Autowired |
| | | private IdentityInfoMapper identityInfoMapper; |
| | | private OrdersRefundMapper ordersRefundMapper; |
| | | |
| | | @Autowired |
| | | private WithdrawalOrdersMapper withdrawalOrdersMapper; |
| | | private OtherOrdersMapper otherOrdersMapper; |
| | | |
| | | @Autowired |
| | | private ReceiveWeightMapper receiveWeightMapper; |
| | | private OrderCommentMapper orderCommentMapper; |
| | | |
| | | @Autowired |
| | | private RevenueMapper revenueMapper; |
| | | |
| | | @Autowired |
| | | private WxMiniUtilService wxMiniUtilService; |
| | | |
| | | @Autowired |
| | | private SendWxMessage sendWxMessage; |
| | | private SystemUserMapper systemUserMapper; |
| | | |
| | | @Autowired |
| | | private AliSmsService aliSmsService; |
| | | private PricingRuleMapper pricingRuleMapper; |
| | | @Autowired |
| | | private RedisTemplate<String, Object> redisTemplate; |
| | | |
| | | @Resource |
| | | private RedisTemplate<String,Object> redisTemplate; |
| | | @Autowired |
| | | private AreasBiz areasBiz; |
| | | |
| | | @Autowired |
| | | private OperationConfigBiz operationConfigBiz; |
| | | |
| | | @Autowired |
| | | private AreasService areasService; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class,BusinessException.class}) |
| | | public OrderReleaseVO create(Orders orders) { |
| | | OrderReleaseVO orderReleaseVO = new OrderReleaseVO(); |
| | | Object objects = null; |
| | | this.initVerification(orders); |
| | | Member member = memberMapper.selectById(orders.getMember().getId()); |
| | | if(Objects.isNull(member)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"用户信息异常"); |
| | | } |
| | | |
| | | orders.setCreateTime(new Date()); |
| | | orders.setUpdateTime(orders.getUpdateTime()); |
| | | orders.setPayStatus(Constants.ZERO); |
| | | orders.setDeleted(Constants.ZERO); |
| | | orders.setReleaseMemberId(orders.getMember().getId()); |
| | | orders.setCommentStatus(Constants.ZERO); |
| | | //查询手续费 |
| | | Category platformCategory = categoryMapper.selectOne(new QueryWrapper<Category>().lambda().eq(Category::getType,Constants.THREE).eq(Category::getName,orders.getType()).eq(Category::getDeleted,Constants.ZERO).last("limit 1 ")); |
| | | if(Objects.isNull(platformCategory)){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"未设置平台配置信息"); |
| | | } |
| | | orders.setPlatformRata(new BigDecimal(platformCategory.getDetail()).divide(new BigDecimal("100"))); |
| | | //订单编号 |
| | | orders.setCode(this.getNextCode(orders.getType())); |
| | | Category category = categoryMapper.selectOne(new QueryWrapper<Category>().lambda() |
| | | .eq(Category::getDeleted,Constants.ZERO).eq(Category::getType,Constants.THREE) |
| | | .eq(Category::getName,orders.getType()) |
| | | .last("limit 1") |
| | | ); |
| | | if(Objects.isNull(category)){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"参数配置错误,请联系管理员"); |
| | | } |
| | | orders.setPayAccount(orders.getEstimatedAccount()); |
| | | Long tcje = Long.valueOf(new BigDecimal(orders.getPayAccount().toString()).multiply(orders.getPlatformRata()).intValue()); |
| | | orders.setReceiveAccount(orders.getPayAccount() - tcje); |
| | | //用餐订单 |
| | | if(Constants.equalsInteger(orders.getType(),Constants.TWO)){ |
| | | orders.setStatus(Constants.ordersStatus.waitPay.getKey()); |
| | | orders.setOutTradeNo(UUID.randomUUID().toString().replace("-","")); |
| | | //唤起支付业务 |
| | | objects = this.getWxPayResponse(orders,member.getOpenid()); |
| | | orderReleaseVO.setObject(objects); |
| | | }else{ |
| | | orders.setStatus(Constants.ordersStatus.wait.getKey()); |
| | | } |
| | | orders.setOriginPriceNum1(orders.getPriceNum1()); |
| | | orders.setOriginPriceNum2(orders.getPriceNum2()); |
| | | orders.setOriginEstimatedAccount(orders.getEstimatedAccount()); |
| | | orders.setConfirmOtherFee(0l); |
| | | public Integer create(Orders orders) { |
| | | ordersMapper.insert(orders); |
| | | |
| | | orderReleaseVO.setId(orders.getId()); |
| | | if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(orders.getMultifileList())){ |
| | | List<Multifile> multifileList = orders.getMultifileList(); |
| | | for (Multifile multifile:multifileList) { |
| | | if(Objects.isNull(multifile) |
| | | || StringUtils.isEmpty(multifile.getFileurl()) |
| | | || StringUtils.isEmpty(multifile.getName())){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"附件信息错误"); |
| | | } |
| | | multifile.setIsdeleted(Constants.ZERO); |
| | | multifile.setCreateDate(new Date()); |
| | | multifile.setObjId(orders.getId()); |
| | | multifile.setObjType(Constants.ONE); |
| | | } |
| | | multifileMapper.insert(multifileList); |
| | | } |
| | | //更新用户发单量 |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda().setSql(" PUBLISH_NUM = ( ifnull(PUBLISH_NUM,0) + 1 )").eq(Member::getId,orders.getMember().getId())); |
| | | |
| | | //创建操作日志 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.UPLOAD; |
| | | String orderTypeInfo = Constants.getOrderInfo(orders);/*"用工单"; |
| | | if(!Constants.equalsInteger(orders.getType(),Constants.ZERO)){ |
| | | orderTypeInfo = Constants.equalsInteger(orders.getType(),Constants.ONE)?"用车单":"送餐单"; |
| | | }else{ |
| | | if(Constants.equalsInteger(orders.getWorkType(),Constants.ZERO)){ |
| | | orderTypeInfo = orderTypeInfo + "-采摘工"; |
| | | }else{ |
| | | orderTypeInfo = orderTypeInfo + (Constants.equalsInteger(orders.getWorkType(),Constants.ONE)?"-分拣工":"-包装工"); |
| | | } |
| | | }*/ |
| | | String logInfo = ordersLog.getInfo() |
| | | .replace("{param}",orderTypeInfo) |
| | | .replace("{userName}", org.apache.commons.lang3.StringUtils.isNotBlank(member.getName())?member.getName():"-"); |
| | | this.saveOrderLog(orders,ordersLog, |
| | | logInfo,orders.getReleaseMemberId(),null); |
| | | return orderReleaseVO; |
| | | return orders.getId(); |
| | | } |
| | | |
| | | private PayResponse getWxPayResponse(Orders orders,String openid){ |
| | | try { |
| | | Object response = null; |
| | | //调起支付 |
| | | WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest(); |
| | | request.setAttach("createOrder"); |
| | | request.setAttach("订单支付"); |
| | | request.setOutTradeNo(orders.getOutTradeNo()); |
| | | request.setTotalFee(BaseWxPayRequest.yuanToFen(orders.getPrice().toString())); |
| | | |
| | | |
| | | request.setTimeStart(DateUtil.DateToString(new Date(), "yyyyMMddHHmmss")); |
| | | request.setSpbillCreateIp(Constants.getIpAddr()); |
| | | //微信小程序 |
| | | request.setOpenid(openid); |
| | | response = WxMiniConfig.wxPayService.createOrder(request); |
| | | PayResponse payResponse = new PayResponse(); |
| | | payResponse.setResponse(response); |
| | | payResponse.setOrderId(orders.getId()); |
| | | payResponse.setPayType(Constants.ZERO); |
| | | |
| | | return payResponse; |
| | | } catch (WxPayException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"支付失败!"); |
| | | } |
| | | |
| | | /** |
| | | * 日志信息 |
| | | * @param orders 订单信息 |
| | | * @param ordersLog 订单支持分类 |
| | | * @param logInfo 日志内容 |
| | | * @param memberId 移动端操作人 |
| | | * @param userId 系统操作人 |
| | | */ |
| | | public void saveOrderLog(Orders orders,Constants.OrdersLog ordersLog,String logInfo,Integer memberId,Integer userId){ |
| | | OrderLog orderLog = new OrderLog(); |
| | | orderLog.setCreateTime(orders.getUpdateTime()); |
| | | orderLog.setDeleted(Constants.ZERO); |
| | | orderLog.setOrderId(orders.getId()); |
| | | orderLog.setTitle(ordersLog.getName()); |
| | | orderLog.setLogInfo(logInfo); |
| | | orderLog.setObjType(ordersLog.getKey()); |
| | | orderLog.setOrderStatus(orders.getStatus()); |
| | | orderLog.setMemberId(memberId); |
| | | orderLog.setCreateUser(userId); |
| | | orderLog.setOptUserType(ordersLog.getUserType()); |
| | | orderLogMapper.insert(orderLog); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | public void initVerification(Orders orders){ |
| | | if(Objects.isNull(orders) |
| | | || Objects.isNull(orders.getType()) |
| | | || Objects.isNull(orders.getStartDate()) |
| | | || Objects.isNull(orders.getEndDate()) |
| | | || StringUtil.isBlank(orders.getLocation()) |
| | | || StringUtil.isBlank(orders.getLinkPhone()) |
| | | || Objects.isNull(orders.getLat()) |
| | | || Objects.isNull(orders.getLgt()) |
| | | || (!Constants.equalsInteger(orders.getType(),Constants.TWO) && Objects.isNull(orders.getCategoryId())) |
| | | || (Constants.equalsInteger(orders.getType(),Constants.ZERO) && Objects.isNull(orders.getWorkType())) |
| | | || Objects.isNull(orders.getPriceNum1()) |
| | | || Objects.isNull(orders.getEstimatedAccount()) |
| | | || Objects.isNull(orders.getPrice()) |
| | | ){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | Integer priceNum2 = orders.getPriceNum2(); |
| | | if( (Constants.equalsInteger(orders.getType(),Constants.ZERO) |
| | | && Constants.equalsInteger(orders.getWorkType(),Constants.TWO) && |
| | | ( Constants.equalsInteger(orders.getCarType(),Constants.ZERO) |
| | | || Constants.equalsInteger(orders.getCarType(),Constants.ONE) )) |
| | | || (Constants.equalsInteger(orders.getType(),Constants.ZERO) |
| | | && Constants.equalsInteger(orders.getWorkType(),Constants.ONE)) |
| | | ){ |
| | | if(Objects.isNull(orders.getPriceNum2())){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | }else{ |
| | | orders.setPriceNum2(Constants.ONE); |
| | | } |
| | | orders.setTotalDays(DateUtil.daysBetweenDates(orders.getEndDate(),orders.getStartDate())+1); |
| | | if(Constants.equalsInteger(orders.getType(),Constants.ZERO)){ |
| | | if(Constants.equalsInteger(orders.getWorkType(),Constants.TWO) |
| | | && ( Objects.isNull(orders.getCarType()) ) ){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | }else if(Constants.equalsInteger(orders.getType(),Constants.ONE)){ |
| | | if(Objects.isNull(orders.getTransportTypeId()) |
| | | || Objects.isNull(orders.getCarType()) |
| | | || Objects.isNull(orders.getTransportNum()) |
| | | || StringUtils.isEmpty(orders.getTransportUnit()) |
| | | || StringUtils.isEmpty(orders.getLocationEnd()) |
| | | || StringUtils.isEmpty(orders.getCarUnit()) |
| | | || Objects.isNull(orders.getLatEnd()) |
| | | || Objects.isNull(orders.getLgtEnd()) |
| | | || CollectionUtils.isEmpty(orders.getWayInfoDTOList()) |
| | | ){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | for (WayInfoDTO wayInfoDTO:orders.getWayInfoDTOList()) { |
| | | if(Objects.isNull(wayInfoDTO) |
| | | ||StringUtils.isEmpty(wayInfoDTO.getLocation()) |
| | | // ||StringUtils.isEmpty(wayInfoDTO.getProvince()) |
| | | // ||StringUtils.isEmpty(wayInfoDTO.getCity()) |
| | | // ||StringUtils.isEmpty(wayInfoDTO.getArea()) |
| | | ||Objects.isNull(wayInfoDTO.getLat()) |
| | | ||Objects.isNull(wayInfoDTO.getLgt()) |
| | | ){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | } |
| | | orders.setWayInfo(JSONObject.toJSONString(orders.getWayInfoDTOList())); |
| | | }else{ |
| | | List<Category> categoryList = categoryMapper.selectList(new QueryWrapper<Category>().lambda().eq(Category::getDeleted,Constants.ZERO) |
| | | .eq(Category::getType,Constants.TWO) |
| | | ); |
| | | if(CollectionUtils.isEmpty(categoryList)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"餐标信息错误"); |
| | | } |
| | | //用餐订单 |
| | | if(CollectionUtils.isEmpty(orders.getCateringDTOList())){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | Long sumPrice = 0L; |
| | | // List<CateringDTO> cateringDTOList = new ArrayList<>(); |
| | | for (CateringDTO cateringDTO:orders.getCateringDTOList()) { |
| | | if(Objects.isNull(cateringDTO) |
| | | || StringUtils.isEmpty(cateringDTO.getName()) |
| | | || Objects.isNull(cateringDTO.getPrice()) |
| | | || Objects.isNull(cateringDTO.getNum()) |
| | | ){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"用餐标准数据错误"); |
| | | } |
| | | //餐标信息 |
| | | List<Category> categories = categoryList.stream().filter(i->Constants.equalsInteger(i.getId(),cateringDTO.getId())).collect(Collectors.toList()); |
| | | if(CollectionUtils.isEmpty(categories)){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"用餐标准数据错误,请刷新重试"); |
| | | } |
| | | Category category = categories.get(Constants.ZERO); |
| | | List<String> priceList = JSONArray.parseArray(category.getDetail(),String.class ); |
| | | if(CollectionUtils.isEmpty(priceList)){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"用餐标准数据错误,请刷新重试"); |
| | | } |
| | | if(priceList.stream().filter(i->((Long.valueOf(i)*100)+"").equals((cateringDTO.getPrice()+""))).collect(Collectors.toList()).size()==Constants.ZERO){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"用餐标准数据错误,请刷新重试"); |
| | | } |
| | | sumPrice = sumPrice + (cateringDTO.getPrice() * cateringDTO.getNum()) ; |
| | | |
| | | } |
| | | if(new BigDecimal(sumPrice.toString()).compareTo(orders.getPrice())!=Constants.ZERO){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"单价计算错误"); |
| | | } |
| | | |
| | | |
| | | orders.setWayInfo(JSONObject.toJSONString(orders.getCateringDTOList())); |
| | | } |
| | | if(!orders.getEstimatedAccount().equals(this.getTotal(orders))){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"金额计算错误!"); |
| | | } |
| | | orders.setPriceNum2(priceNum2); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void deleteById(Integer id) { |
| | | ordersMapper.deleteById(id); |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getDeleted, Constants.ONE) |
| | | .eq(Orders::getId, id)); |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | @Override |
| | | public void deleteByIdInBatch(List<Integer> ids) { |
| | | if (CollectionUtils.isEmpty(ids)) { |
| | | if (ids == null || ids.isEmpty()) { |
| | | return; |
| | | } |
| | | ordersMapper.deleteBatchIds(ids); |
| | | } |
| | | |
| | | @Override |
| | | public void update(Orders orders){ |
| | | if(Objects.isNull(orders) |
| | | || Objects.isNull(orders.getId())){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | Orders model = ordersMapper.selectById(orders.getId()); |
| | | if(!Constants.equalsInteger(model.getReleaseMemberId(),orders.getMember().getId())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"非您的订单无法进行该操作"); |
| | | } |
| | | if(Constants.equalsInteger(model.getIsUpdate(),Constants.ONE)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单已修改,待接单方确认,无法进行该操作"); |
| | | } |
| | | if(!Constants.equalsInteger(model.getType(),Constants.TWO)){ |
| | | if(Constants.equalsInteger(model.getStatus(),Constants.ZERO) |
| | | ||Constants.equalsInteger(model.getStatus(),Constants.ONE)){ |
| | | this.updateById(orders); |
| | | }else if(Constants.equalsInteger(model.getStatus(),Constants.TWO)){ |
| | | this.updOrderData(orders,model); |
| | | }else{ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED); |
| | | } |
| | | }else{ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | // @Override |
| | | @Transactional(rollbackFor = {BusinessException.class,Exception.class}) |
| | | public void updateById(Orders orders) { |
| | | |
| | | Orders model = ordersMapper.selectById(orders.getId()); |
| | | if(Constants.equalsInteger(model.getType(),Constants.TWO)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"此类订单无法进行修改"); |
| | | } |
| | | if(!Constants.equalsInteger(model.getStatus(),Constants.ONE)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单状态已流转,无法进行该操作"); |
| | | } |
| | | this.initVerification(orders); |
| | | orders.setUpdateTime(new Date()); |
| | | Category category = categoryMapper.selectOne(new QueryWrapper<Category>().lambda() |
| | | .eq(Category::getDeleted,Constants.ZERO).eq(Category::getType,Constants.THREE) |
| | | .eq(Category::getName,orders.getType()) |
| | | .last("limit 1") |
| | | ); |
| | | if(Objects.isNull(category)){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"参数配置错误,请联系管理员"); |
| | | } |
| | | multifileMapper.update(new UpdateWrapper<Multifile>().lambda().set(Multifile::getIsdeleted,Constants.ONE).eq(Multifile::getObjType,Constants.ONE) |
| | | .eq(Multifile::getObjId,orders.getId())); |
| | | if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(orders.getMultifileList())){ |
| | | List<Multifile> multifileList = orders.getMultifileList(); |
| | | for (Multifile multifile:multifileList) { |
| | | if(Objects.isNull(multifile) |
| | | || Objects.isNull(multifile.getObjType()) |
| | | || StringUtils.isEmpty(multifile.getFileurl()) |
| | | || StringUtils.isEmpty(multifile.getName())){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"附件信息错误"); |
| | | } |
| | | multifile.setId(null); |
| | | multifile.setIsdeleted(Constants.ZERO); |
| | | multifile.setCreateDate(new Date()); |
| | | multifile.setObjId(orders.getId()); |
| | | multifile.setObjType(Constants.ONE); |
| | | } |
| | | multifileMapper.insert(multifileList); |
| | | } |
| | | orders.setOriginPriceNum1(orders.getPriceNum1()); |
| | | orders.setOriginPriceNum2(orders.getPriceNum2()); |
| | | orders.setOriginEstimatedAccount(orders.getEstimatedAccount()); |
| | | orders.setPayAccount(orders.getEstimatedAccount()); |
| | | orders.setConfirmOtherFee(0L); |
| | | ordersMapper.updateById(orders); |
| | | } |
| | | |
| | | @Override |
| | | public void updateByIdInBatch(List<Orders> orderss) { |
| | | if (CollectionUtils.isEmpty(orderss)) { |
| | | public void updateByIdInBatch(List<Orders> ordersList) { |
| | | if (ordersList == null || ordersList.isEmpty()) { |
| | | return; |
| | | } |
| | | for (Orders orders: orderss) { |
| | | //this.updateById(orders); |
| | | for (Orders orders : ordersList) { |
| | | this.updateById(orders); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public Orders findById(Integer id) { |
| | | Orders orders = ordersMapper.selectJoinOne(Orders.class,new MPJLambdaWrapper<Orders>() |
| | | .selectAll(Orders.class) |
| | | .select(" m1.name " , Orders::getReleaseName) |
| | | .select(" m1.telephone " , Orders::getReleasePhone) |
| | | .select(" case when i.AUTH_TYPE = 0 then i.LINK_NAME else i.COMPANY_NAME end " , Orders::getAcceptName) |
| | | .select(" i.TELEPHONE " , Orders::getAcceptPhone) |
| | | .select("c1.name",Orders::getCategoryName) |
| | | .select("c2.name",Orders::getTransportTypeName) |
| | | .leftJoin(" category c1 on t.category_id = c1.id ") |
| | | .leftJoin(" category c2 on t.TRANSPORT_TYPE_ID = c2.id ") |
| | | .leftJoin("member m1 on t.RELEASE_MEMBER_ID = m1.id ") |
| | | .leftJoin("member m2 on t.ACCEPT_MEMBER_ID = m2.id ") |
| | | .leftJoin("identity_info i on m2.id = i.MEMBER_ID and i.TYPE = t.type and i.AUDIT_STATUS = 2 ") |
| | | .eq(Orders::getDeleted,Constants.ZERO) |
| | | .eq(Orders::getId,id) |
| | | .orderByDesc(Orders::getId)); |
| | | if(Objects.isNull(orders)){ |
| | | Orders orders = ordersMapper.selectById(id); |
| | | if (Objects.isNull(orders)) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | orders.setStatusName(Constants.ordersStatus.getName(orders.getStatus())); |
| | | this.getPriceUnit(orders); |
| | | |
| | | //附件信息 |
| | | List<Multifile> multifileList = multifileMapper.selectList(new QueryWrapper<Multifile>().lambda().eq(Multifile::getObjId,orders.getId()) |
| | | .eq(Multifile::getIsdeleted,Constants.ZERO).eq(Multifile::getObjType,Constants.ONE).orderByAsc(Multifile::getId)); |
| | | if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(multifileList)){ |
| | | String path = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RESOURCE_PATH).getCode() |
| | | +systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.ORDERS_FILES).getCode(); |
| | | for (Multifile multifile:multifileList) { |
| | | multifile.setFileurlFull(path + multifile.getFileurl()); |
| | | } |
| | | orders.setMultifileList(multifileList); |
| | | } |
| | | //订单流转记录 |
| | | List<OrderLog> orderLogList = orderLogMapper.selectList(new QueryWrapper<OrderLog>().lambda() |
| | | .eq(OrderLog::getDeleted,Constants.ZERO) |
| | | .eq(OrderLog::getOrderId,orders.getId()) |
| | | .orderByAsc(OrderLog::getCreateTime) |
| | | ); |
| | | if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(orderLogList)){ |
| | | for (OrderLog orderLog:orderLogList) { |
| | | if(Constants.equalsInteger(orderLog.getOptUserType(),Constants.ZERO)&& org.apache.commons.lang3.StringUtils.isNotBlank(orders.getReleaseName())){ |
| | | orderLog.setLogInfo(orderLog.getLogInfo().replace("{userName}",orders.getReleaseName())); |
| | | }else if(Constants.equalsInteger(orderLog.getOptUserType(),Constants.ONE)&& org.apache.commons.lang3.StringUtils.isNotBlank(orders.getAcceptName())){ |
| | | orderLog.setLogInfo(orderLog.getLogInfo().replace("{userName}",orders.getAcceptName())); |
| | | } |
| | | } |
| | | orders.setOrderLogList(orderLogList); |
| | | } |
| | | return orders; |
| | | } |
| | | |
| | | public void getPriceUnit(Orders orders){ |
| | | if(Constants.equalsInteger(orders.getType(),Constants.ZERO)){ |
| | | if(Constants.equalsInteger(orders.getWorkType(),Constants.ZERO)){ |
| | | orders.setPriceUnit("元/斤"); |
| | | }else if(Constants.equalsInteger(orders.getWorkType(),Constants.ONE)){ |
| | | orders.setPriceUnit("元/人/天"); |
| | | }else{ |
| | | if(Constants.equalsInteger(orders.getCarType(),Constants.ZERO)){ |
| | | orders.setPriceUnit("元/人/天"); |
| | | }else if(Constants.equalsInteger(orders.getCarType(),Constants.ONE)){ |
| | | orders.setPriceUnit("元/人/小时"); |
| | | }else{ |
| | | orders.setPriceUnit("元/斤"); |
| | | } |
| | | } |
| | | }else if(Constants.equalsInteger(orders.getType(),Constants.ONE)){ |
| | | if(Constants.equalsInteger(orders.getCarType(),Constants.ZERO)){ |
| | | orders.setPriceUnit("元/天"); |
| | | }else if(Constants.equalsInteger(orders.getCarType(),Constants.ONE)){ |
| | | orders.setPriceUnit("元/次"); |
| | | } |
| | | } |
| | | } |
| | | @Override |
| | | public Orders findOne(Orders orders) { |
| | | QueryWrapper<Orders> wrapper = new QueryWrapper<>(orders); |
| | |
| | | QueryWrapper<Orders> wrapper = new QueryWrapper<>(orders); |
| | | return ordersMapper.selectList(wrapper); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public PageData<Orders> findPage(PageWrap<Orders> pageWrap) { |
| | | IPage<Orders> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); |
| | | MPJLambdaWrapper<Orders> queryWrapper = new MPJLambdaWrapper<Orders>(); |
| | | MPJLambdaWrapper<Orders> queryWrapper = new MPJLambdaWrapper<Orders>() |
| | | .selectAll(Orders.class) |
| | | .selectAs(Category::getDetail, Orders::getOrderLevel) |
| | | .select("s1.name", Orders::getDepositShopName) |
| | | .leftJoin(Category.class, Category::getId, Orders::getGoodType) |
| | | .leftJoin(DriverInfo.class, DriverInfo::getId, Orders::getAcceptDriver) |
| | | .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID") |
| | | .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID"); |
| | | ; |
| | | Utils.MP.blankToNull(pageWrap.getModel()); |
| | | Orders model = pageWrap.getModel(); |
| | | queryWrapper.selectAll(Orders.class) |
| | | .select(" m1.name " , Orders::getReleaseName) |
| | | .select(" m1.telephone " , Orders::getReleasePhone) |
| | | .select(" case when i.AUTH_TYPE = 0 then i.LINK_NAME else i.COMPANY_NAME end " , Orders::getAcceptName) |
| | | .select(" i.TELEPHONE " , Orders::getAcceptPhone) |
| | | .select("c1.name",Orders::getCategoryName) |
| | | .select("c2.name",Orders::getTransportTypeName) |
| | | .leftJoin(" category c1 on t.category_id = c1.id ") |
| | | .leftJoin(" category c2 on t.TRANSPORT_TYPE_ID = c2.id ") |
| | | .leftJoin("member m1 on t.RELEASE_MEMBER_ID = m1.id ") |
| | | .leftJoin("member m2 on t.ACCEPT_MEMBER_ID = m2.id ") |
| | | .leftJoin("identity_info i on m2.id = i.MEMBER_ID and i.TYPE = t.type and i.AUDIT_STATUS = 2 ") |
| | | .eq(Orders::getDeleted,Constants.ZERO) |
| | | .orderByDesc(Orders::getId) |
| | | ; |
| | | queryWrapper.ge(Objects.nonNull(model.getCreateTimeStart()),Orders::getCreateTime, Utils.Date.getStart(model.getCreateTimeStart())); |
| | | queryWrapper.le(Objects.nonNull(model.getCreateTimeEnd()),Orders::getCreateTime, Utils.Date.getEnd(model.getCreateTimeEnd())); |
| | | queryWrapper.ge(Objects.nonNull(model.getAcceptTimeStart()),Orders::getAcceptTime, Utils.Date.getStart(model.getAcceptTimeStart())); |
| | | queryWrapper.le(Objects.nonNull(model.getAcceptTimeEnd()),Orders::getAcceptTime, Utils.Date.getEnd(model.getAcceptTimeEnd())); |
| | | queryWrapper.ge(Objects.nonNull(model.getDoneTimeStart()),Orders::getFinishTime, Utils.Date.getStart(model.getDoneTimeStart())); |
| | | queryWrapper.le(Objects.nonNull(model.getDoneTimeEnd()),Orders::getFinishTime, Utils.Date.getEnd(model.getDoneTimeEnd())); |
| | | queryWrapper.like(org.apache.commons.lang3.StringUtils.isNotBlank(model.getCode()),Orders::getCode, model.getCode()); |
| | | queryWrapper.eq(Objects.nonNull(model.getType()),Orders::getType, model.getType()); |
| | | queryWrapper.eq(Objects.nonNull(model.getStatus()),Orders::getStatus, model.getStatus()); |
| | | queryWrapper.eq(Objects.nonNull(model.getCommentStatus()),Orders::getCommentStatus, model.getCommentStatus()); |
| | | queryWrapper.eq(Objects.nonNull(model.getReleaseMemberId()),Orders::getReleaseMemberId, model.getReleaseMemberId()); |
| | | queryWrapper.eq(Objects.nonNull(model.getAcceptMemberId()),Orders::getAcceptMemberId, model.getAcceptMemberId()); |
| | | queryWrapper.eq(Objects.nonNull(model.getAcceptType()),Orders::getAcceptType, model.getAcceptType()); |
| | | queryWrapper.apply(org.apache.commons.lang3.StringUtils.isNotBlank(model.getReleaseName()),"m1.name like '%"+model.getReleaseName()+"%' or m1.TELEPHONE like '%"+model.getReleaseName()+"%' "); |
| | | queryWrapper.apply(org.apache.commons.lang3.StringUtils.isNotBlank(model.getAcceptName()),"( i.LINK_NAME like '%"+model.getAcceptName()+"%' or i.company_name like '%"+model.getAcceptName()+"%' or i.TELEPHONE like '%"+model.getAcceptName()+"%' ) "); |
| | | IPage<Orders> iPage = ordersMapper.selectJoinPage(page,Orders.class,queryWrapper); |
| | | for (Orders orders:iPage.getRecords()) { |
| | | this.getOrderContent(orders); |
| | | orders.setStatusName(Constants.ordersStatus.getName(orders.getStatus())); |
| | | orders.setEstimatedAccountYuan(Objects.nonNull(orders.getEstimatedAccount())&&orders.getEstimatedAccount()>0?orders.getEstimatedAccount()/100:0L); |
| | | orders.setPayAccountYuan(Objects.nonNull(orders.getPayAccount())&&orders.getPayAccount()>0?orders.getPayAccount()/100:0L); |
| | | } |
| | | return PageData.from(iPage); |
| | | } |
| | | |
| | | public void getOrderContent(Orders orders){ |
| | | if(Constants.equalsInteger(orders.getType(),Constants.ZERO)){ |
| | | orders.setOrderContent(Constants.workType.getName(orders.getWorkType()) +" | " + orders.getCategoryName()); |
| | | if(Constants.equalsInteger(orders.getWorkType(),Constants.ZERO)){ |
| | | if(Objects.nonNull(orders.getPriceNum1())){ |
| | | orders.setOrderContent(orders.getOrderContent()+" | " +orders.getPriceNum1()+"斤"); |
| | | } |
| | | }else if(Constants.equalsInteger(orders.getWorkType(),Constants.ONE)){ |
| | | if(Objects.nonNull(orders.getPriceNum2())) { |
| | | orders.setOrderContent(orders.getOrderContent() + " | " + orders.getPriceNum2() + "人"); |
| | | } |
| | | }else{ |
| | | if(Constants.equalsInteger(orders.getCarType(),Constants.ZERO)||Constants.equalsInteger(orders.getCarType(),Constants.ONE)){ |
| | | if(Objects.nonNull(orders.getPriceNum2())) { |
| | | orders.setOrderContent(orders.getOrderContent() + " | " + orders.getPriceNum2() + "人"); |
| | | } |
| | | }else{ |
| | | if(Objects.nonNull(orders.getPriceNum1())) { |
| | | orders.setOrderContent(orders.getOrderContent() + " | " + orders.getPriceNum1() + "斤"); |
| | | } |
| | | } |
| | | } |
| | | }else if(Constants.equalsInteger(orders.getType(),Constants.ONE)){ |
| | | if(org.apache.commons.lang3.StringUtils.isNotBlank(orders.getCategoryName())){ |
| | | orders.setOrderContent( orders.getCategoryName() + |
| | | (StringUtils.isEmpty(orders.getTransportTypeName())?"":" | " + orders.getTransportTypeName() ) + |
| | | (Objects.isNull(orders.getTransportNum())?null:" | " + orders.getTransportNum() +"斤")); |
| | | } |
| | | |
| | | if(Constants.equalsInteger(orders.getCarType(),Constants.ZERO)){ |
| | | if(Objects.nonNull(orders.getPriceNum2())) { |
| | | orders.setOrderContent(orders.getOrderContent() + " | 用车" + orders.getPriceNum1() + "天"); |
| | | } |
| | | }else{ |
| | | if(Objects.nonNull(orders.getPriceNum2())) { |
| | | orders.setOrderContent(orders.getOrderContent() + " | 用车" + orders.getPriceNum1() + "次"); |
| | | } |
| | | } |
| | | }else{ |
| | | if(org.apache.commons.lang3.StringUtils.isNotBlank(orders.getWayInfo())){ |
| | | List<CateringDTO> cateringDTOList = JSONArray.parseArray(orders.getWayInfo(),CateringDTO.class); |
| | | if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(cateringDTOList)){ |
| | | for (CateringDTO cateringDTO:cateringDTOList) { |
| | | if(StringUtils.isEmpty(orders.getOrderContent())){ |
| | | orders.setOrderContent(cateringDTO.getName()+(new BigDecimal(cateringDTO.getPrice().toString()).divide(new BigDecimal("100"),2,BigDecimal.ROUND_HALF_UP))+" 需"+cateringDTO.getNum()+"份"); |
| | | }else{ |
| | | orders.setOrderContent(orders.getOrderContent()+" | "+cateringDTO.getName()+(new BigDecimal(cateringDTO.getPrice().toString()).divide(new BigDecimal("100"),2,BigDecimal.ROUND_HALF_UP))+" 需"+cateringDTO.getNum()+"份"); |
| | | } |
| | | } |
| | | } |
| | | pageWrap.getModel().setDeleted(Constants.ZERO); |
| | | queryWrapper.eq(pageWrap.getModel().getDeleted() != null, Orders::getDeleted, pageWrap.getModel().getDeleted()); |
| | | queryWrapper.like(StringUtils.isNotBlank(pageWrap.getModel().getCode()), Orders::getCode, pageWrap.getModel().getCode()); |
| | | queryWrapper.like(StringUtils.isNotBlank(pageWrap.getModel().getDepositShopName()), "s1.name", pageWrap.getModel().getDepositShopName()); |
| | | queryWrapper.like(StringUtils.isNotBlank(pageWrap.getModel().getTakeShopName()), "s2.name", pageWrap.getModel().getTakeShopName()); |
| | | queryWrapper.like(StringUtils.isNotBlank(pageWrap.getModel().getGoodsInfo()), Orders::getGoodsInfo, pageWrap.getModel().getGoodsInfo()); |
| | | queryWrapper.ge(pageWrap.getModel().getCreateStartTime() != null, Orders::getCreateTime, Utils.Date.getStart(pageWrap.getModel().getCreateStartTime())); |
| | | queryWrapper.le(pageWrap.getModel().getCreateEndTime() != null, Orders::getCreateTime, Utils.Date.getEnd(pageWrap.getModel().getCreateEndTime())); |
| | | queryWrapper.eq(pageWrap.getModel().getDepositShopId() != null, Orders::getDepositShopId, pageWrap.getModel().getDepositShopId()); |
| | | queryWrapper.eq(pageWrap.getModel().getType() != null, Orders::getType, pageWrap.getModel().getType()); |
| | | queryWrapper.eq(pageWrap.getModel().getStatus() != null, Orders::getStatus, pageWrap.getModel().getStatus()); |
| | | 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())); |
| | | for (PageWrap.SortData sortData : pageWrap.getSorts()) { |
| | | if (sortData.getDirection().equalsIgnoreCase(PageWrap.DESC)) { |
| | | queryWrapper.orderByDesc(sortData.getProperty()); |
| | | } else { |
| | | queryWrapper.orderByAsc(sortData.getProperty()); |
| | | } |
| | | } |
| | | |
| | | return PageData.from(ordersMapper.selectJoinPage(page, Orders.class, queryWrapper)); |
| | | } |
| | | |
| | | @Override |
| | | public OrderSummaryVO findSummary(PageWrap<Orders> pageWrap) { |
| | | // 构建与findPage相同的查询条件 |
| | | MPJLambdaWrapper<Orders> queryWrapper = new MPJLambdaWrapper<Orders>() |
| | | .leftJoin(Category.class, Category::getId, Orders::getGoodType) |
| | | .leftJoin(DriverInfo.class, DriverInfo::getId, Orders::getAcceptDriver) |
| | | .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID") |
| | | .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID"); |
| | | Utils.MP.blankToNull(pageWrap.getModel()); |
| | | pageWrap.getModel().setDeleted(Constants.ZERO); |
| | | queryWrapper.eq(pageWrap.getModel().getDeleted() != null, Orders::getDeleted, pageWrap.getModel().getDeleted()); |
| | | queryWrapper.like(StringUtils.isNotBlank(pageWrap.getModel().getCode()), Orders::getCode, pageWrap.getModel().getCode()); |
| | | queryWrapper.like(StringUtils.isNotBlank(pageWrap.getModel().getDepositShopName()), "s1.name", pageWrap.getModel().getDepositShopName()); |
| | | queryWrapper.like(StringUtils.isNotBlank(pageWrap.getModel().getTakeShopName()), "s2.name", pageWrap.getModel().getTakeShopName()); |
| | | queryWrapper.like(StringUtils.isNotBlank(pageWrap.getModel().getGoodsInfo()), Orders::getGoodsInfo, pageWrap.getModel().getGoodsInfo()); |
| | | queryWrapper.ge(pageWrap.getModel().getCreateStartTime() != null, Orders::getCreateTime, Utils.Date.getStart(pageWrap.getModel().getCreateStartTime())); |
| | | queryWrapper.le(pageWrap.getModel().getCreateEndTime() != null, Orders::getCreateTime, Utils.Date.getEnd(pageWrap.getModel().getCreateEndTime())); |
| | | queryWrapper.eq(pageWrap.getModel().getDepositShopId() != null, Orders::getDepositShopId, pageWrap.getModel().getDepositShopId()); |
| | | queryWrapper.eq(pageWrap.getModel().getType() != null, Orders::getType, pageWrap.getModel().getType()); |
| | | queryWrapper.eq(pageWrap.getModel().getStatus() != null, Orders::getStatus, pageWrap.getModel().getStatus()); |
| | | 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.select( |
| | | "IFNULL(SUM(t.total_amount), 0) as total_amount_sum", |
| | | "IFNULL(SUM(CASE WHEN t.settlement_status = 1 THEN t.total_amount ELSE 0 END), 0) as settled_total_amount_sum", |
| | | "IFNULL(SUM(t.driver_fee), 0) as driver_fee_sum", |
| | | "IFNULL(SUM(CASE WHEN t.settlement_status = 1 THEN t.driver_fee ELSE 0 END), 0) as settled_driver_fee_sum" |
| | | ); |
| | | queryWrapper.groupBy("1=1"); |
| | | |
| | | List<Map<String, Object>> result = ordersMapper.selectJoinMaps(queryWrapper); |
| | | OrderSummaryVO vo = new OrderSummaryVO(); |
| | | if (result != null && !result.isEmpty()) { |
| | | Map<String, Object> row = result.get(0); |
| | | vo.setTotalAmountSum(toLong(row.get("total_amount_sum"))); |
| | | vo.setSettledTotalAmountSum(toLong(row.get("settled_total_amount_sum"))); |
| | | vo.setDriverFeeSum(toLong(row.get("driver_fee_sum"))); |
| | | vo.setSettledDriverFeeSum(toLong(row.get("settled_driver_fee_sum"))); |
| | | } else { |
| | | vo.setTotalAmountSum(0L); |
| | | vo.setSettledTotalAmountSum(0L); |
| | | vo.setDriverFeeSum(0L); |
| | | vo.setSettledDriverFeeSum(0L); |
| | | } |
| | | return vo; |
| | | } |
| | | |
| | | private Long toLong(Object val) { |
| | | if (val == null) return 0L; |
| | | if (val instanceof Number) return ((Number) val).longValue(); |
| | | return Long.parseLong(val.toString()); |
| | | } |
| | | |
| | | @Override |
| | | public BigDecimal calculateInsuranceFee(BigDecimal declaredValue) { |
| | | if (declaredValue == null || declaredValue.compareTo(BigDecimal.ZERO) <= 0) { |
| | | return BigDecimal.ZERO; |
| | | } |
| | | String rateStr = systemDictDataBiz.queryByCode(Constants.OPERATION_CONFIG, Constants.OP_INSURANCE_RATE).getCode(); |
| | | BigDecimal rate = new BigDecimal(rateStr); |
| | | return declaredValue.multiply(rate).setScale(2, BigDecimal.ROUND_HALF_UP); |
| | | } |
| | | |
| | | /** |
| | | * 计算就地存取预估费用 |
| | | * |
| | | * 计算规则: |
| | | * 1. 根据城市+物品类型 查询 pricing_rule(type=0),fieldA=categoryId, fieldB=单价(分/天) |
| | | * 2. 每项小计 = 单价 × 数量 × 天数 |
| | | * 3. 物品价格 = 各项小计之和 |
| | | * 4. 保价费用 = 报价金额 × 保价费率(字典 INSURANCE_RATE),元转分 |
| | | * 5. 总价格 = 物品价格 + 保价费用 |
| | | * |
| | | * @param dto 就地存取计价请求参数 |
| | | * @return 价格计算结果 |
| | | */ |
| | | @Override |
| | | public PriceCalculateVO calculateLocalPrice(CalculateLocalPriceDTO dto) { |
| | | // 天数校验,最少1天 |
| | | int days = dto.getEstimatedDepositDays() != null && dto.getEstimatedDepositDays() > 0 |
| | | ? dto.getEstimatedDepositDays() : 1; |
| | | |
| | | // 收集所有物品类型ID |
| | | List<Integer> categoryIds = new ArrayList<>(); |
| | | for (OrderItemDTO item : dto.getItems()) { |
| | | categoryIds.add(item.getCategoryId()); |
| | | } |
| | | |
| | | // 批量查询计价规则 pricing_rule type=0:fieldA=categoryId, fieldB=单价(分/天) |
| | | List<String> fieldAList = new ArrayList<>(); |
| | | for (Integer cid : categoryIds) { |
| | | fieldAList.add(String.valueOf(cid)); |
| | | } |
| | | List<PricingRule> rules = pricingRuleMapper.selectList(new QueryWrapper<PricingRule>().lambda() |
| | | .eq(PricingRule::getDeleted, Constants.ZERO) |
| | | .eq(PricingRule::getType, Constants.ZERO) |
| | | .eq(PricingRule::getCityId, dto.getCityId()) |
| | | .in(PricingRule::getFieldA, fieldAList)); |
| | | Map<String, PricingRule> ruleMap = new HashMap<>(); |
| | | for (PricingRule r : rules) { |
| | | ruleMap.put(r.getFieldA(), r); |
| | | } |
| | | |
| | | // 批量查询物品类型名称 |
| | | List<Category> categories = categoryMapper.selectBatchIds(categoryIds); |
| | | Map<Integer, String> categoryNameMap = new HashMap<>(); |
| | | Map<Integer, String> categoryDetailMap = new HashMap<>(); |
| | | for (Category c : categories) { |
| | | categoryNameMap.put(c.getId(), c.getName()); |
| | | categoryDetailMap.put(c.getId(), c.getDetail()); |
| | | } |
| | | |
| | | // 计算每项物品费用:小计 = 单价 × 数量 × 天数 |
| | | List<ItemPriceVO> itemList = new ArrayList<>(); |
| | | long itemPriceTotal = 0L; |
| | | |
| | | for (OrderItemDTO item : dto.getItems()) { |
| | | PricingRule rule = ruleMap.get(String.valueOf(item.getCategoryId())); |
| | | if (rule == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), |
| | | "未找到该城市物品类型的计价规则"); |
| | | } |
| | | |
| | | long unitPrice = Long.parseLong(rule.getFieldB()); |
| | | long subtotal = unitPrice * item.getQuantity() * days; |
| | | |
| | | ItemPriceVO vo = new ItemPriceVO(); |
| | | vo.setCategoryId(item.getCategoryId()); |
| | | vo.setCategoryName(categoryNameMap.getOrDefault(item.getCategoryId(), "")); |
| | | vo.setDetail(categoryDetailMap.get(item.getCategoryId())); |
| | | vo.setQuantity(item.getQuantity()); |
| | | vo.setUnitPrice(unitPrice); |
| | | vo.setLocallyPrice(unitPrice); |
| | | vo.setSubtotal(subtotal); |
| | | itemList.add(vo); |
| | | |
| | | itemPriceTotal += subtotal; |
| | | } |
| | | |
| | | // 保价费用:报价金额 × 保价费率(字典 INSURANCE_RATE),元→分 |
| | | long insuranceFeeFen = 0L; |
| | | if (Boolean.TRUE.equals(dto.getInsured()) && dto.getDeclaredAmount() != null) { |
| | | BigDecimal insuranceFeeYuan = calculateInsuranceFee(dto.getDeclaredAmount()); |
| | | insuranceFeeFen = insuranceFeeYuan.multiply(new BigDecimal(100)).longValue(); |
| | | } |
| | | |
| | | // 总价格 = 物品价格 + 保价费用 |
| | | long totalPrice = itemPriceTotal + insuranceFeeFen; |
| | | |
| | | PriceCalculateVO result = new PriceCalculateVO(); |
| | | result.setItemList(itemList); |
| | | result.setItemPrice(itemPriceTotal); |
| | | result.setInsuranceFee(insuranceFeeFen); |
| | | result.setTotalPrice(totalPrice); |
| | | result.setDays(days); |
| | | result.setUrgentFee(0L); |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 计算异地存取预估费用 |
| | | * |
| | | * 计算规则: |
| | | * 1. 调用腾讯地图API计算寄件点与取件点的驾车距离(米→公里) |
| | | * 2. 根据城市+物品类型 查询 pricing_rule(type=1): |
| | | * fieldB=起步距离(km), fieldC=起步价(分), fieldD=超出距离单位(km), fieldE=超出距离单价(分) |
| | | * 3. 每项运费单价: |
| | | * - 距离 ≤ 起步距离 → 单价 = 起步价 |
| | | * - 距离 > 起步距离 → 单价 = 起步价 + ceil((距离-起步距离)/超出距离单位) × 超出距离单价 |
| | | * 4. 小计 = 运费单价 × 数量 |
| | | * 5. 物品价格 = 各项小计之和 |
| | | * 6. 保价费用 = 报价金额 × 保价费率(字典 INSURANCE_RATE),元转分 |
| | | * 7. 加急费用 = 物品价格 × 加急系数(字典 URGENT_COEFFICIENT) |
| | | * 8. 总价格 = 物品价格 + 保价费用 + 加急费用 |
| | | * |
| | | * @param dto 异地存取计价请求参数 |
| | | * @return 价格计算结果 |
| | | */ |
| | | @Override |
| | | public PriceCalculateVO calculateRemotePrice(CalculateRemotePriceDTO dto) { |
| | | // 1. 调用腾讯地图距离矩阵API计算驾车距离 |
| | | String from = dto.getFromLat() + "," + dto.getFromLgt(); |
| | | String to = dto.getToLat() + "," + dto.getToLgt(); |
| | | JSONObject distanceResult = MapUtil.distanceSingle("driving", from, to); |
| | | BigDecimal distance = distanceResult.getBigDecimal("distance"); |
| | | // distance 单位为米,转为公里 |
| | | BigDecimal distanceKm = distance.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP); |
| | | |
| | | // 收集所有物品类型ID |
| | | List<Integer> categoryIds = new ArrayList<>(); |
| | | for (OrderItemDTO item : dto.getItems()) { |
| | | categoryIds.add(item.getCategoryId()); |
| | | } |
| | | |
| | | // 2. 批量查询配送计价规则 pricing_rule type=1 |
| | | List<String> fieldAList = new ArrayList<>(); |
| | | for (Integer cid : categoryIds) { |
| | | fieldAList.add(String.valueOf(cid)); |
| | | } |
| | | List<PricingRule> rules = pricingRuleMapper.selectList(new QueryWrapper<PricingRule>().lambda() |
| | | .eq(PricingRule::getDeleted, Constants.ZERO) |
| | | .eq(PricingRule::getType, Constants.ONE) |
| | | .eq(PricingRule::getCityId, dto.getCityId()) |
| | | .in(PricingRule::getFieldA, fieldAList)); |
| | | Map<String, PricingRule> ruleMap = new HashMap<>(); |
| | | for (PricingRule r : rules) { |
| | | ruleMap.put(r.getFieldA(), r); |
| | | } |
| | | |
| | | // 查询就地存取计价规则 pricing_rule type=0,用于获取 locallyPrice |
| | | List<PricingRule> localRules = pricingRuleMapper.selectList(new QueryWrapper<PricingRule>().lambda() |
| | | .eq(PricingRule::getDeleted, Constants.ZERO) |
| | | .eq(PricingRule::getType, Constants.ZERO) |
| | | .eq(PricingRule::getCityId, dto.getCityId()) |
| | | .in(PricingRule::getFieldA, fieldAList)); |
| | | Map<String, PricingRule> localRuleMap = new HashMap<>(); |
| | | for (PricingRule r : localRules) { |
| | | localRuleMap.put(r.getFieldA(), r); |
| | | } |
| | | |
| | | // 批量查询物品类型名称 |
| | | List<Category> categories = categoryMapper.selectBatchIds(categoryIds); |
| | | Map<Integer, String> categoryNameMap = new HashMap<>(); |
| | | Map<Integer, String> categoryDetailMap = new HashMap<>(); |
| | | for (Category c : categories) { |
| | | categoryNameMap.put(c.getId(), c.getName()); |
| | | categoryDetailMap.put(c.getId(), c.getDetail()); |
| | | } |
| | | |
| | | // 3. 逐项计算运费:起步价 + 超出部分阶梯价 |
| | | List<ItemPriceVO> itemList = new ArrayList<>(); |
| | | long itemPriceTotal = 0L; |
| | | |
| | | for (OrderItemDTO item : dto.getItems()) { |
| | | PricingRule rule = ruleMap.get(String.valueOf(item.getCategoryId())); |
| | | if (rule == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), |
| | | "未找到该城市物品类型的配送计价规则"); |
| | | } |
| | | |
| | | // fieldB=起步距离(km), fieldC=起步价(分), fieldD=超出距离单位(km), fieldE=超出距离单价(分) |
| | | BigDecimal startDistance = new BigDecimal(rule.getFieldB()); |
| | | long startPrice = Long.parseLong(rule.getFieldC()); |
| | | BigDecimal extraDistanceUnit = new BigDecimal(rule.getFieldD()); |
| | | long extraPricePerUnit = Long.parseLong(rule.getFieldE()); |
| | | |
| | | // 阶梯计价:距离 ≤ 起步距离取起步价,超出按 ceil(超出距离/单位) × 单价累加 |
| | | long unitPrice; |
| | | if (distanceKm.compareTo(startDistance) <= 0) { |
| | | unitPrice = startPrice; |
| | | } else { |
| | | BigDecimal extraKm = distanceKm.subtract(startDistance); |
| | | BigDecimal extraCount = extraKm.divide(extraDistanceUnit, 0, RoundingMode.CEILING); |
| | | unitPrice = startPrice + extraCount.longValue() * extraPricePerUnit; |
| | | } |
| | | |
| | | long subtotal = unitPrice * item.getQuantity(); |
| | | |
| | | // 就地存取单价 |
| | | PricingRule localRule = localRuleMap.get(String.valueOf(item.getCategoryId())); |
| | | Long locallyPrice = localRule != null ? Long.parseLong(localRule.getFieldB()) : null; |
| | | |
| | | ItemPriceVO vo = new ItemPriceVO(); |
| | | vo.setCategoryId(item.getCategoryId()); |
| | | vo.setCategoryName(categoryNameMap.getOrDefault(item.getCategoryId(), "")); |
| | | vo.setDetail(categoryDetailMap.get(item.getCategoryId())); |
| | | vo.setQuantity(item.getQuantity()); |
| | | vo.setUnitPrice(unitPrice); |
| | | vo.setLocallyPrice(locallyPrice); |
| | | vo.setSubtotal(subtotal); |
| | | vo.setStartDistance(startDistance); |
| | | vo.setStartPrice(startPrice); |
| | | vo.setExtraDistance(extraDistanceUnit); |
| | | vo.setExtraPrice(extraPricePerUnit); |
| | | itemList.add(vo); |
| | | |
| | | itemPriceTotal += subtotal; |
| | | } |
| | | |
| | | // 4. 保价费用:报价金额 × 保价费率(字典 INSURANCE_RATE),元→分 |
| | | long insuranceFeeFen = 0L; |
| | | if (Boolean.TRUE.equals(dto.getInsured()) && dto.getDeclaredAmount() != null) { |
| | | BigDecimal insuranceFeeYuan = calculateInsuranceFee(dto.getDeclaredAmount()); |
| | | insuranceFeeFen = insuranceFeeYuan.multiply(new BigDecimal(100)).longValue(); |
| | | } |
| | | |
| | | // 5. 加急费用:物品价格 × 加急系数(字典 URGENT_COEFFICIENT) |
| | | long urgentFeeFen = 0L; |
| | | if (Boolean.TRUE.equals(dto.getUrgent())) { |
| | | String urgentRateStr = systemDictDataBiz.queryByCode( |
| | | Constants.OPERATION_CONFIG, Constants.OP_URGENT_COEFFICIENT).getCode(); |
| | | BigDecimal urgentRate = new BigDecimal(urgentRateStr); |
| | | urgentFeeFen = new BigDecimal(itemPriceTotal).multiply(urgentRate) |
| | | .setScale(0, RoundingMode.HALF_UP).longValue(); |
| | | } |
| | | |
| | | // 6. 总价格 = 物品价格 + 保价费用 + 加急费用 |
| | | long totalPrice = itemPriceTotal + insuranceFeeFen + urgentFeeFen; |
| | | |
| | | PriceCalculateVO result = new PriceCalculateVO(); |
| | | result.setItemList(itemList); |
| | | result.setItemPrice(itemPriceTotal); |
| | | result.setInsuranceFee(insuranceFeeFen); |
| | | result.setUrgentFee(urgentFeeFen); |
| | | result.setTotalPrice(totalPrice); |
| | | result.setDistance(distanceKm); |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public long count(Orders orders) { |
| | |
| | | return ordersMapper.selectCount(wrapper); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 手动接单 |
| | | * @param orderId |
| | | * 创建订单 |
| | | * |
| | | * 业务流程: |
| | | * 1. 参数校验:必填字段、时间顺序、物品不重复、异地必填服务时效 |
| | | * 2. 查询寄件店铺信息(获取经纬度、地址) |
| | | * 3. 调用计价接口计算费用(calculateLocalPrice / calculateRemotePrice) |
| | | * 4. 生成订单编号:JC + yyyyMMddHHmmss + 4位随机数 |
| | | * 5. 创建订单主表 Orders(状态=待支付) |
| | | * 6. 创建订单明细表 OrdersDetail(每项物品尺寸) |
| | | * 7. 创建附件记录 Multifile(物品图片 objType=12) |
| | | * |
| | | * @param dto 创建订单请求参数 |
| | | * @param memberId 当前登录会员ID |
| | | * @return 订单ID |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = {BusinessException.class,Exception.class}) |
| | | public void accept(Integer orderId,Member member){ |
| | | Orders orders = ordersMapper.selectById(orderId); |
| | | if(Objects.isNull(orders)||Constants.equalsInteger(orders.getDeleted(),Constants.ONE)){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public PayResponse createOrder(CreateOrderDTO dto, Integer memberId) { |
| | | String lockKey = Constants.GOODS_ORDER_CREATE_LOCK + memberId; |
| | | //判断前端是否在同一页面创建了两次订单 |
| | | if (redisTemplate.hasKey(lockKey)) { |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"正在创建订单,请勿重复调用!"); |
| | | } else { |
| | | redisTemplate.opsForValue().set(lockKey, "", 5, TimeUnit.SECONDS); |
| | | } |
| | | if(!Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.wait.getKey())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单状态已流转,无法进行该操作"); |
| | | Date now = new Date(); |
| | | // ========== 1. 参数校验 ========== |
| | | // 预计到店存件时间必须小于预计到店取件时间 |
| | | java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm"); |
| | | Date depositTime; |
| | | Date takeTime; |
| | | try { |
| | | depositTime = sdf.parse(dto.getExpectedDepositTime()); |
| | | takeTime = sdf.parse(dto.getExpectedTakeTime()); |
| | | } catch (java.text.ParseException e) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "时间格式错误,正确格式:yyyy-MM-dd HH:mm"); |
| | | } |
| | | if(Constants.equalsInteger(orders.getReleaseMemberId(),member.getId())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"您自己的订单无法进行该操作"); |
| | | } |
| | | member = memberMapper.selectById(member.getId()); |
| | | //查询用户是否有对应身份 |
| | | if(Constants.equalsInteger(orders.getType(),Constants.ZERO)){ |
| | | if(!Constants.equalsInteger(member.getWorkerIdentity(),Constants.TWO)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"您还未注册该服务,请前往\"我的\"页面提交申请"); |
| | | } |
| | | }else if(Constants.equalsInteger(orders.getType(),Constants.ONE)){ |
| | | if(!Constants.equalsInteger(member.getDriverIdentity(),Constants.TWO)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"您还未注册该服务,请前往\"我的\"页面提交申请"); |
| | | } |
| | | }else{ |
| | | if(!Constants.equalsInteger(member.getChefIdentity(),Constants.TWO)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"您还未注册该服务,请前往\"我的\"页面提交申请"); |
| | | } |
| | | if (!depositTime.before(takeTime)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "预计到店存件时间必须小于预计到店取件时间"); |
| | | } |
| | | |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda().eq(Orders::getId,orders.getId()) |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .set(Orders::getAcceptType,Constants.ZERO) |
| | | .set(Orders::getAcceptTime,new Date()) |
| | | .set(Orders::getAcceptMemberId,member.getId()) |
| | | .set(Orders::getStatus,Constants.ordersStatus.accept.getKey()) |
| | | ); |
| | | |
| | | //更新接单量 |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda().setSql(" RECEIVE_NUM = (ifnull(RECEIVE_NUM,0) + 1 )").eq(Member::getId,member.getId())); |
| | | |
| | | //创建操作日志 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.RECEIVE; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),member.getId(),null); |
| | | |
| | | IdentityInfo wokerIdentityInfo = identityInfoMapper.selectOne(new QueryWrapper<IdentityInfo>().lambda() |
| | | .eq(IdentityInfo::getMemberId,member.getId()) |
| | | .eq(IdentityInfo::getType,orders.getType()) |
| | | .eq(IdentityInfo::getAuditStatus,Constants.TWO) |
| | | .last("limit 1") |
| | | ); |
| | | Member releaseMember = memberMapper.selectById(orders.getReleaseMemberId()); |
| | | |
| | | if(Objects.nonNull(releaseMember)){ |
| | | if(org.apache.commons.lang3.StringUtils.isNotBlank(releaseMember.getOpenid())&&Objects.nonNull(wokerIdentityInfo)){ |
| | | //发送微信通知 |
| | | sendWxMessage.acceptMessage(releaseMember.getOpenid(),orders,wokerIdentityInfo.getLinkName(),wokerIdentityInfo.getTelephone()); |
| | | // 物品尺寸不能重复 |
| | | List<Integer> categoryIds = new ArrayList<>(); |
| | | for (OrderItemDTO item : dto.getItems()) { |
| | | if (categoryIds.contains(item.getCategoryId())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "物品尺寸不能重复"); |
| | | } |
| | | if(org.apache.commons.lang3.StringUtils.isNotBlank(orders.getLinkPhone())){ |
| | | //短信通知 |
| | | aliSmsService.businessSendSms(Constants.smsContent.accept.getKey(),orders.getLinkPhone(),orders,null, |
| | | wokerIdentityInfo,categoryMapper); |
| | | } |
| | | categoryIds.add(item.getCategoryId()); |
| | | } |
| | | |
| | | // 物品图片最多3张 |
| | | if (dto.getGoodsImages() != null && dto.getGoodsImages().size() > 3) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "物品图片最多3张"); |
| | | } |
| | | |
| | | // ========== 2. 校验物品类型 ========== |
| | | Category goodTypeCategory = categoryMapper.selectById(dto.getGoodType()); |
| | | if (goodTypeCategory == null || Constants.equalsInteger(goodTypeCategory.getDeleted(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "物品类型不存在"); |
| | | } |
| | | if (!Constants.equalsInteger(goodTypeCategory.getType(), Constants.TWO)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "物品类型参数错误"); |
| | | } |
| | | |
| | | // ========== 3. 查询寄件店铺信息 ========== |
| | | ShopInfo depositShop = shopInfoMapper.selectById(dto.getDepositShopId()); |
| | | if (depositShop == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "寄件店铺不存在"); |
| | | } |
| | | |
| | | // ========== 4. 计算费用 ========== |
| | | |
| | | // 异地寄存:校验取件点 |
| | | BigDecimal takeLat = null; |
| | | BigDecimal takeLgt = null; |
| | | String takeLocationValue = null; |
| | | ShopInfo takeShop = null; |
| | | if (Constants.ONE.equals(dto.getType())) { |
| | | // 异地必填服务时效 |
| | | if (dto.getIsUrgent() == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "异地寄存服务时效不能为空"); |
| | | } |
| | | // 取件点:店铺 or 自选点,至少提供一组 |
| | | if (dto.getTakeShopId() != null) { |
| | | takeShop = shopInfoMapper.selectById(dto.getTakeShopId()); |
| | | if (takeShop == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "取件店铺不存在"); |
| | | } |
| | | takeLat = BigDecimal.valueOf(takeShop.getLatitude()); |
| | | takeLgt = BigDecimal.valueOf(takeShop.getLongitude()); |
| | | takeLocationValue = takeShop.getAddress(); |
| | | } else if (dto.getTakeLat() != null && dto.getTakeLgt() != null && StringUtils.isNotBlank(dto.getTakeLocation())) { |
| | | takeLat = dto.getTakeLat(); |
| | | takeLgt = dto.getTakeLgt(); |
| | | takeLocationValue = dto.getTakeLocation(); |
| | | } else { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请选择取件店铺或输入自选取件地址"); |
| | | } |
| | | } else { |
| | | // 就地存取:取件门店同寄件门店 |
| | | takeShop = depositShop; |
| | | } |
| | | |
| | | // ========== 3. 计算费用 ========== |
| | | PriceCalculateVO priceResult; |
| | | if (Constants.ZERO.equals(dto.getType())) { |
| | | // 就地寄存:计算天数 |
| | | long diffMs = takeTime.getTime() - depositTime.getTime(); |
| | | int days = (int) Math.max(1, (diffMs / (1000 * 60 * 60 * 24)) + 1); |
| | | |
| | | CalculateLocalPriceDTO priceDTO = new CalculateLocalPriceDTO(); |
| | | priceDTO.setCityId(dto.getCityId()); |
| | | priceDTO.setEstimatedDepositDays(days); |
| | | priceDTO.setItems(dto.getItems()); |
| | | priceDTO.setInsured(dto.getDeclaredAmount() != null && dto.getDeclaredAmount().compareTo(BigDecimal.ZERO) > 0); |
| | | priceDTO.setDeclaredAmount(dto.getDeclaredAmount()); |
| | | priceResult = calculateLocalPrice(priceDTO); |
| | | } else { |
| | | // 异地寄存 |
| | | CalculateRemotePriceDTO priceDTO = new CalculateRemotePriceDTO(); |
| | | priceDTO.setCityId(dto.getCityId()); |
| | | priceDTO.setFromLat(BigDecimal.valueOf(depositShop.getLatitude())); |
| | | priceDTO.setFromLgt(BigDecimal.valueOf(depositShop.getLongitude())); |
| | | priceDTO.setToLat(takeLat); |
| | | priceDTO.setToLgt(takeLgt); |
| | | priceDTO.setItems(dto.getItems()); |
| | | priceDTO.setInsured(dto.getDeclaredAmount() != null && dto.getDeclaredAmount().compareTo(BigDecimal.ZERO) > 0); |
| | | priceDTO.setDeclaredAmount(dto.getDeclaredAmount()); |
| | | priceDTO.setUrgent(Constants.ONE.equals(dto.getIsUrgent())); |
| | | priceResult = calculateRemotePrice(priceDTO); |
| | | } |
| | | |
| | | // ========== 5. 生成订单编号 ========== |
| | | String orderCode = "JC" + new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(now) |
| | | + String.format("%04d", new java.util.Random().nextInt(10000)); |
| | | // 生成32位唯一第三方订单编号 |
| | | String orderTradeNo = generateOrderTradeNo(); |
| | | |
| | | // ========== 6. 创建订单主表 ========== |
| | | Orders orders = new Orders(); |
| | | orders.setCode(orderCode); |
| | | orders.setOutTradeNo(orderTradeNo); |
| | | orders.setMemberId(memberId); |
| | | orders.setType(dto.getType()); |
| | | orders.setCityId(String.valueOf(dto.getCityId())); |
| | | orders.setStatus(Constants.ZERO); // 待支付 |
| | | orders.setPayStatus(Constants.ZERO); // 未支付 |
| | | orders.setCommentStatus(Constants.ZERO); // 未评价 |
| | | orders.setSettlementStatus(Constants.ZERO); // 未结算 |
| | | orders.setDeleted(Constants.ZERO); |
| | | orders.setCreateTime(now); |
| | | orders.setUpdateTime(now); |
| | | |
| | | // 寄件信息 |
| | | orders.setDepositShopId(dto.getDepositShopId()); |
| | | // 存件地点:省市区全路径 + 地址描述 |
| | | String depositLocationRemark = depositShop.getAddress(); |
| | | if (depositShop.getAreaId() != null) { |
| | | Areas depositArea = areasBiz.resolveArea(depositShop.getAreaId()); |
| | | if (depositArea != null) { |
| | | depositLocationRemark = depositArea.getProvinceName() + depositArea.getCityName() + depositArea.getName() + depositShop.getAddress(); |
| | | } |
| | | } |
| | | orders.setDepositLocation(depositLocationRemark); |
| | | orders.setDepositLocationRemark(depositShop.getAddress()); |
| | | orders.setDepositLat(BigDecimal.valueOf(depositShop.getLatitude())); |
| | | orders.setDepositLgt(BigDecimal.valueOf(depositShop.getLongitude())); |
| | | |
| | | // 取件信息 |
| | | orders.setTakeUser(dto.getTakeUser()); |
| | | orders.setTakePhone(dto.getTakePhone()); |
| | | orders.setExpectedDepositTime(depositTime); |
| | | orders.setExpectedTakeTime(takeTime); |
| | | // 计算预计存放天数 |
| | | long dayDiff = (takeTime.getTime() - depositTime.getTime()) / (1000 * 60 * 60 * 24); |
| | | orders.setEstimatedDepositDays((int) Math.max(1, dayDiff + 1)); |
| | | |
| | | if (Constants.ONE.equals(dto.getType())) { |
| | | // 异地:取件点信息 |
| | | orders.setTakeShopId(dto.getTakeShopId()); |
| | | orders.setTakeLocation(takeLocationValue); |
| | | orders.setTakeLat(takeLat); |
| | | orders.setTakeLgt(takeLgt); |
| | | orders.setIsUrgent(dto.getIsUrgent()); |
| | | } else { |
| | | // 就地:取件点同寄件店铺 |
| | | orders.setTakeShopId(dto.getDepositShopId()); |
| | | orders.setTakeLocation(depositShop.getAddress()); |
| | | orders.setTakeLat(BigDecimal.valueOf(depositShop.getLatitude())); |
| | | orders.setTakeLgt(BigDecimal.valueOf(depositShop.getLongitude())); |
| | | orders.setIsUrgent(Constants.ZERO); |
| | | } |
| | | |
| | | // 物品信息 |
| | | orders.setGoodType(dto.getGoodType()); |
| | | // 拼接物品信息:物品类型名称、尺寸名称*数量(数组字符串) |
| | | List<String> goodsParts = new ArrayList<>(); |
| | | for (ItemPriceVO itemVO : priceResult.getItemList()) { |
| | | goodsParts.add(itemVO.getCategoryName() + "*" + itemVO.getQuantity()); |
| | | } |
| | | orders.setGoodsInfo(goodTypeCategory.getName() + "、" + String.join(",", goodsParts)); |
| | | orders.setRemark(dto.getRemark()); |
| | | orders.setSelfTake(Constants.ZERO); |
| | | |
| | | // 费用信息(分) |
| | | orders.setBasicAmount(priceResult.getItemPrice()); |
| | | orders.setEstimatedAmount(priceResult.getTotalPrice()); |
| | | orders.setTotalAmount(priceResult.getTotalPrice()); |
| | | orders.setUrgentAmount(priceResult.getUrgentFee()); |
| | | if (dto.getDeclaredAmount() != null && dto.getDeclaredAmount().compareTo(BigDecimal.ZERO) > 0) { |
| | | orders.setDeclaredAmount(dto.getDeclaredAmount().multiply(new BigDecimal(100)).longValue()); |
| | | } else { |
| | | orders.setDeclaredAmount(0L); |
| | | } |
| | | orders.setDeclaredFee(priceResult.getInsuranceFee()); |
| | | orders.setPrice(priceResult.getItemPrice()); |
| | | |
| | | // 薪酬计算与占比存储 |
| | | calculateAndSetFeeAllocation(orders, depositShop, takeShop); |
| | | |
| | | ordersMapper.insert(orders); |
| | | Integer orderId = orders.getId(); |
| | | |
| | | // ========== 7. 创建订单明细 ========== |
| | | for (ItemPriceVO itemVO : priceResult.getItemList()) { |
| | | OrdersDetail detail = new OrdersDetail(); |
| | | detail.setOrderId(orderId); |
| | | detail.setLuggageId(itemVO.getCategoryId()); |
| | | detail.setLuggageName(itemVO.getCategoryName()); |
| | | detail.setLuggageDetail(itemVO.getDetail()); |
| | | detail.setNum(itemVO.getQuantity()); |
| | | detail.setUnitPrice(itemVO.getUnitPrice()); |
| | | detail.setStartDistance(itemVO.getStartDistance()); |
| | | detail.setStartPrice(itemVO.getStartPrice()); |
| | | detail.setExtraDistance(itemVO.getExtraDistance()); |
| | | detail.setExtraPrice(itemVO.getExtraPrice()); |
| | | detail.setLocallyPrice(itemVO.getLocallyPrice()); |
| | | detail.setDeleted(Constants.ZERO); |
| | | detail.setCreateTime(now); |
| | | ordersDetailMapper.insert(detail); |
| | | } |
| | | // ========== 8. 保存物品图片附件 ========== |
| | | if (dto.getGoodsImages() != null && !dto.getGoodsImages().isEmpty()) { |
| | | int sortNum = 1; |
| | | for (String imgUrl : dto.getGoodsImages()) { |
| | | Multifile multifile = new Multifile(); |
| | | multifile.setObjId(orderId); |
| | | multifile.setObjType(Constants.FileType.ORDER_FILE.getKey()); |
| | | multifile.setType(Constants.ZERO); |
| | | multifile.setFileurl(imgUrl); |
| | | multifile.setIsdeleted(Constants.ZERO); |
| | | multifile.setCreateDate(now); |
| | | multifile.setSortnum(sortNum++); |
| | | multifileMapper.insert(multifile); |
| | | } |
| | | } |
| | | // ========== 9. 唤起微信支付 ========== |
| | | Member member = memberMapper.selectById(memberId); |
| | | if (member == null || StringUtils.isBlank(member.getOpenid())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "用户信息异常,无法发起支付"); |
| | | } |
| | | PayResponse payResponse = wxPay(orders, member.getOpenid(), Constants.OrdersAttach.STORAGE_ORDER); |
| | | payResponse.setLockKey(lockKey); |
| | | return payResponse; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 开始作业 |
| | | * @param orderId |
| | | * @param member |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = {BusinessException.class,Exception.class}) |
| | | public void begin(Integer orderId,Member member){ |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public PayResponse continuePay(Integer orderId, Integer memberId) { |
| | | // 1. 查询订单 |
| | | Orders orders = ordersMapper.selectById(orderId); |
| | | if(Objects.isNull(orders)||Constants.equalsInteger(orders.getDeleted(),Constants.ONE)){ |
| | | if (Objects.isNull(orders) || Constants.equalsInteger(orders.getDeleted(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | if(!Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.accept.getKey())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单状态已流转,无法进行该操作"); |
| | | // 2. 校验订单归属 |
| | | if (!Constants.equalsInteger(orders.getMemberId(), memberId)) { |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "无权操作该订单"); |
| | | } |
| | | if(!Constants.equalsInteger(orders.getReleaseMemberId(),member.getId())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"非您的订单无法进行该操作"); |
| | | // 3. 校验订单状态:仅待支付可继续支付 |
| | | if (!Constants.equalsInteger(orders.getStatus(), Constants.ZERO)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不支持继续支付"); |
| | | } |
| | | if(Constants.equalsInteger(orders.getIsUpdate(),Constants.ONE)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单修改待确认,无法进行该操作"); |
| | | // 4. 校验支付金额 |
| | | if (orders.getTotalAmount() == null || orders.getTotalAmount() <= 0) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单金额异常,无法发起支付"); |
| | | } |
| | | if(orders.getStartDate().getTime()>System.currentTimeMillis()){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单未到开始时间无法进行该操作"); |
| | | } |
| | | // 5. 重新生成第三方订单编号(避免重复) |
| | | String orderTradeNo = generateOrderTradeNo(); |
| | | orders.setOutTradeNo(orderTradeNo); |
| | | orders.setUpdateTime(new Date()); |
| | | orders.setStatus(Constants.ordersStatus.doing.getKey()); |
| | | orders.setWorkStartTime(new Date()); |
| | | ordersMapper.updateById(orders); |
| | | |
| | | //创建操作日志 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.BEGIN; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),member.getId(),null); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 发单方修改订单 - 已接单状态 |
| | | */ |
| | | // @Override |
| | | @Transactional(rollbackFor = {BusinessException.class,Exception.class}) |
| | | public void updOrderData(Orders orders,Orders model){ |
| | | if(Objects.isNull(orders) |
| | | || Objects.isNull(orders.getStartDate()) |
| | | || Objects.isNull(orders.getEndDate())){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | // 6. 唤起微信支付 |
| | | Member member = memberMapper.selectById(memberId); |
| | | if (member == null || StringUtils.isBlank(member.getOpenid())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "用户信息异常,无法发起支付"); |
| | | } |
| | | model.setTotalDays(DateUtil.daysBetweenDates(orders.getEndDate(),orders.getStartDate())+1); |
| | | model.setStartDate(orders.getStartDate()); |
| | | model.setEndDate(orders.getEndDate()); |
| | | //用车类型 |
| | | if(Constants.equalsInteger(model.getType(),Constants.ONE)){ |
| | | if(Constants.equalsInteger(model.getCarType(),Constants.ZERO)) { |
| | | model.setPriceNum1(orders.getTotalDays()); |
| | | } |
| | | }else if(Constants.equalsInteger(model.getType(),Constants.ZERO)){ |
| | | if(Constants.equalsInteger(model.getWorkType(),Constants.ONE)|| |
| | | (Constants.equalsInteger(model.getWorkType(),Constants.TWO)&&Constants.equalsInteger(model.getCarType(),Constants.ZERO))){ |
| | | model.setPriceNum1(orders.getTotalDays()); |
| | | } |
| | | }else{ |
| | | model.setPriceNum1(orders.getTotalDays()); |
| | | } |
| | | Long total = this.getTotal(orders); |
| | | Long tcje = Long.valueOf(new BigDecimal(total.toString()).multiply(model.getPlatformRata()).intValue()); |
| | | Long reciveTotal = total - tcje; |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getStartDate,model.getStartDate()) |
| | | .set(Orders::getEndDate,model.getEndDate()) |
| | | .set(Orders::getTotalDays,model.getTotalDays()) |
| | | .set(Orders::getIsUpdate,Constants.ONE) |
| | | .set(Orders::getIsUpdateTime,new Date()) |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .set(Orders::getEstimatedAccount,total) |
| | | .set(Orders::getOriginEstimatedAccount,total) |
| | | .set(Orders::getReceiveAccount,reciveTotal) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | //创建操作日志 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.UPD_ORDER; |
| | | this.saveOrderLog(model,ordersLog, |
| | | ordersLog.getInfo(),orders.getMember().getId(),null); |
| | | |
| | | //通知接单人 订单发生变更 |
| | | Member member = memberMapper.selectById(model.getAcceptMemberId()); |
| | | if(Objects.nonNull(member)){ |
| | | if(org.apache.commons.lang3.StringUtils.isNotBlank(member.getOpenid())){ |
| | | model.setStartDate(orders.getStartDate()); |
| | | model.setEndDate(orders.getEndDate()); |
| | | //发送微信通知 |
| | | sendWxMessage.orderUpdMessage(member.getOpenid(),model); |
| | | } |
| | | IdentityInfo wokerIdentityInfo = identityInfoMapper.selectOne(new QueryWrapper<IdentityInfo>().lambda() |
| | | .eq(IdentityInfo::getMemberId,member.getId()) |
| | | .eq(IdentityInfo::getType,orders.getType()) |
| | | .eq(IdentityInfo::getAuditStatus,Constants.TWO) |
| | | .last("limit 1") |
| | | ); |
| | | if(Objects.nonNull(wokerIdentityInfo)){ |
| | | //短信通知 |
| | | aliSmsService.businessSendSms(Constants.smsContent.orderUpd.getKey(),wokerIdentityInfo.getTelephone(),orders,null, |
| | | null,categoryMapper); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public Long getTotal(Orders orders){ |
| | | if(Objects.isNull(orders) |
| | | ||Objects.isNull(orders.getPrice()) |
| | | ||Objects.isNull(orders.getPriceNum1()) |
| | | ||Objects.isNull(orders.getType()) |
| | | ){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | BigDecimal bigDecimalPrice = BigDecimal.ZERO; |
| | | if( |
| | | (Constants.equalsInteger(orders.getType(),Constants.ZERO) && Constants.equalsInteger(orders.getWorkType(),Constants.ZERO )) |
| | | || (Constants.equalsInteger(orders.getType(),Constants.ZERO) && Objects.nonNull(orders.getCarType()) && Constants.equalsInteger(orders.getWorkType(),Constants.TWO ) && Constants.equalsInteger(orders.getCarType(),Constants.TWO)) |
| | | || Constants.equalsInteger(orders.getType(),Constants.ONE) |
| | | || Constants.equalsInteger(orders.getType(),Constants.TWO) |
| | | ){ |
| | | bigDecimalPrice = orders.getPrice().multiply(new BigDecimal(orders.getPriceNum1().toString())); |
| | | }else{ |
| | | if(Objects.isNull(orders.getPriceNum2())){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | bigDecimalPrice = orders.getPrice().multiply(new BigDecimal(orders.getPriceNum1().toString())).multiply(new BigDecimal(orders.getPriceNum2().toString())); |
| | | } |
| | | if(Objects.nonNull(orders.getConfirmOtherFee())){ |
| | | bigDecimalPrice = bigDecimalPrice.add(new BigDecimal(orders.getConfirmOtherFee().toString())); |
| | | } |
| | | return bigDecimalPrice.divide(new BigDecimal("1"),0,BigDecimal.ROUND_HALF_UP).longValue();//orders.getPrice() * orders.getPriceNum1() * orders.getPriceNum2(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 接单方确认订单费用 |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = {BusinessException.class,Exception.class}) |
| | | public void confirmFee(ConfirmFeeOrderDTO confirmUpdOrderDTO){ |
| | | if(Objects.isNull(confirmUpdOrderDTO) |
| | | || Objects.isNull(confirmUpdOrderDTO.getOrderId()) |
| | | || Objects.isNull(confirmUpdOrderDTO.getPriceNum1())){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | Orders orders = ordersMapper.selectById(confirmUpdOrderDTO.getOrderId()); |
| | | if(Objects.isNull(orders)||Constants.equalsInteger(orders.getDeleted(),Constants.ONE)){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | if(!Constants.equalsInteger(orders.getAcceptMemberId(),confirmUpdOrderDTO.getMember().getId())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"非您的订单无法进行该操作"); |
| | | } |
| | | if(!Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.doing.getKey())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单状态已流转,无法进行该操作"); |
| | | } |
| | | //类型:0=用工;1=运货;2=订餐 |
| | | if(Constants.equalsInteger(orders.getType(),Constants.ZERO)){ |
| | | //用工类型:0=采摘工;1=分拣工;2=包装工;(用工订单) |
| | | if(Constants.equalsInteger(orders.getWorkType(),Constants.ONE)){ |
| | | //1=分拣工 |
| | | if( Objects.isNull(confirmUpdOrderDTO.getPriceNum2())){//必须有用工数量(人) |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | }else if(Constants.equalsInteger(orders.getWorkType(),Constants.TWO)){ |
| | | //包装工 用车类型(用工包装/运货使用):0=天;1=次/小时;2=重量 |
| | | if( !Constants.equalsInteger(orders.getCarType(),Constants.TWO) |
| | | && Objects.isNull(confirmUpdOrderDTO.getPriceNum2())){ |
| | | //不是按重量计费的,必须有用工数量(人) |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | } |
| | | }else if(Constants.equalsInteger(orders.getType(),Constants.ONE)){ |
| | | //运货订单 |
| | | |
| | | }else{ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"该订单不支持该操作,请返回刷新重试!"); |
| | | } |
| | | orders.setPriceNum1(confirmUpdOrderDTO.getPriceNum1()); |
| | | orders.setPriceNum2(confirmUpdOrderDTO.getPriceNum2()); |
| | | orders.setConfirmOtherFee(confirmUpdOrderDTO.getConfirmOtherFee()); |
| | | Long totalFee = this.getTotal(orders);//重新计算费用 |
| | | Long payFee = totalFee;//重新计算费用 |
| | | Long tcje = Long.valueOf(new BigDecimal(orders.getPayAccount().toString()).multiply(orders.getPlatformRata()).intValue()); |
| | | Long reciveTotal = payFee - tcje; |
| | | //BigDecimal recFee = new BigDecimal(payFee).multiply((new BigDecimal(1).subtract(Constants.formatBigDecimal(orders.getPlatformRata())))).setScale(0, RoundingMode.HALF_UP) ; |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getPriceNum1,confirmUpdOrderDTO.getPriceNum1()) |
| | | .set(Orders::getPriceNum2,confirmUpdOrderDTO.getPriceNum2()) |
| | | .set(Orders::getConfirmFeeRemark,confirmUpdOrderDTO.getConfirmFeeRemark()) |
| | | .set(Orders::getConfirmOtherFee,confirmUpdOrderDTO.getConfirmOtherFee()) |
| | | .set(Orders::getEstimatedAccount,totalFee) |
| | | .set(Orders::getStatus,Constants.ordersStatus.feeconfirm.getKey()) |
| | | .set(Orders::getPayAccount,payFee) |
| | | .set(Orders::getReceiveAccount,reciveTotal) |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .set(Orders::getConfirmFeeTime,new Date()) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | //记录同意修改的日志 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.FEE_CONFIRM; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),confirmUpdOrderDTO.getMember().getId(),null); |
| | | |
| | | //微信通知 |
| | | Member member = memberMapper.selectById(orders.getReleaseMemberId()); |
| | | if(Objects.nonNull(member)&& org.apache.commons.lang3.StringUtils.isNotBlank(member.getOpenid())){ |
| | | sendWxMessage.waitPayMessage(member.getOpenid(),orders); |
| | | } |
| | | |
| | | return wxPay(orders, member.getOpenid(), Constants.OrdersAttach.STORAGE_ORDER); |
| | | } |
| | | |
| | | /** |
| | | * 接单方处理订单修改 |
| | | * @param confirmUpdOrderDTO |
| | | * 唤起微信小程序支付 |
| | | * |
| | | * @param orders 订单实体(需要 code、totalAmount) |
| | | * @param openid 用户微信openid |
| | | * @param ordersAttach 订单支付类型 |
| | | * @return PayResponse 包含微信调起参数和订单主键 |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = {BusinessException.class,Exception.class}) |
| | | public void confirmUpd(ConfirmUpdOrderDTO confirmUpdOrderDTO){ |
| | | if(Objects.isNull(confirmUpdOrderDTO) |
| | | || Objects.isNull(confirmUpdOrderDTO.getOrderId()) |
| | | || Objects.isNull(confirmUpdOrderDTO.getStatus()) |
| | | || !(Constants.equalsInteger(confirmUpdOrderDTO.getStatus(),Constants.ONE)|| |
| | | Constants.equalsInteger(confirmUpdOrderDTO.getStatus(),Constants.ZERO)) |
| | | ){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | Orders orders = ordersMapper.selectById(confirmUpdOrderDTO.getOrderId()); |
| | | if(Objects.isNull(orders)||Constants.equalsInteger(orders.getDeleted(),Constants.ONE)){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | if(!Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.accept.getKey())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单状态已流转,无法进行该操作"); |
| | | } |
| | | if(!Constants.equalsInteger(orders.getIsUpdate(),Constants.ONE)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单修改状态已流转,无法进行该操作"); |
| | | } |
| | | if(!Constants.equalsInteger(orders.getAcceptMemberId(),confirmUpdOrderDTO.getMember().getId())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"非您的订单无法进行该操作"); |
| | | } |
| | | if(!Constants.equalsInteger(confirmUpdOrderDTO.getStatus(),Constants.ONE)){ |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getIsUpdate,Constants.TWO) |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | //记录同意修改的日志 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.UPD_AGREE; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),confirmUpdOrderDTO.getMember().getId(),null); |
| | | }else{ |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getIsUpdate,Constants.TWO) |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .set(Orders::getStatus,Constants.ordersStatus.wait.getKey()) |
| | | .set(Orders::getAcceptMemberId,null) |
| | | .set(Orders::getAcceptType,null) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | private PayResponse wxPay(Orders orders, String openid, Constants.OrdersAttach ordersAttach) { |
| | | try { |
| | | WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest(); |
| | | request.setBody(ordersAttach.getName()); |
| | | request.setAttach(ordersAttach.getKey()); |
| | | request.setOutTradeNo(orders.getOutTradeNo()); |
| | | // totalAmount 单位为分,WeChat Pay setTotalFee 也是分,直接转int |
| | | long totalFee = orders.getTotalAmount() != null ? orders.getTotalAmount() : 0L; |
| | | request.setTotalFee((int) totalFee); |
| | | request.setTimeStart(DateUtil.DateToString(new Date(), "yyyyMMddHHmmss")); |
| | | request.setSpbillCreateIp(Constants.getIpAddr()); |
| | | request.setOpenid(openid); |
| | | |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda().setSql("receive_num = receive_num - 1").eq(Member::getId,confirmUpdOrderDTO.getMember().getId())); |
| | | Object response = WxMiniConfig.wxPayService.createOrder(request); |
| | | |
| | | //记录不同意修改的日志 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.UPD_DISAGREE; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),confirmUpdOrderDTO.getMember().getId(),null); |
| | | PayResponse payResponse = new PayResponse(); |
| | | payResponse.setResponse(response); |
| | | payResponse.setOrderId(orders.getId()); |
| | | return payResponse; |
| | | } catch (WxPayException e) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "支付调起失败:" + e.getMessage()); |
| | | } |
| | | //短信通知 |
| | | aliSmsService.businessSendSms(!Constants.equalsInteger(confirmUpdOrderDTO.getStatus(),Constants.ONE)? |
| | | Constants.smsContent.agreeUpd.getKey():Constants.smsContent.disAgreeUpd.getKey() |
| | | ,orders.getLinkPhone(),null,null, |
| | | null,categoryMapper); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void cancelOrder(Integer orderId,Member member){ |
| | | Orders orders = ordersMapper.selectById(orderId); |
| | | if(Objects.isNull(orders)||Constants.equalsInteger(orders.getDeleted(),Constants.ONE)){ |
| | | public OrderDetailVO findDetail(Integer id) { |
| | | Orders order = ordersMapper.selectById(id); |
| | | if (Objects.isNull(order)) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | if(Constants.equalsInteger(orders.getReleaseMemberId(),member.getId())){ |
| | | this.releaseCancelOrder(orders,member); |
| | | }else if(Constants.equalsInteger(orders.getAcceptMemberId(),member.getId())){ |
| | | this.receiveCancelOrder(orders,member); |
| | | }else{ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"非您的订单无法进行该操作"); |
| | | |
| | | OrderDetailVO vo = new OrderDetailVO(); |
| | | vo.setOrder(order); |
| | | |
| | | // 图片路径前缀 |
| | | String imgPrefix = getOrdersPrefix(); |
| | | |
| | | // 下单图片 (type=12) |
| | | vo.setOrderFiles(getFileUrls(id, Constants.FileType.ORDER_FILE.getKey(), imgPrefix)); |
| | | |
| | | // 会员信息 |
| | | if (order.getMemberId() != null) { |
| | | Member member = memberMapper.selectById(order.getMemberId()); |
| | | if (member != null) { |
| | | vo.setMemberName(member.getName()); |
| | | vo.setMemberPhone(member.getTelephone()); |
| | | } |
| | | } |
| | | |
| | | // 寄存门店信息 |
| | | if (order.getDepositShopId() != null) { |
| | | ShopInfo depositShop = shopInfoMapper.selectById(order.getDepositShopId()); |
| | | if (depositShop != null) { |
| | | vo.setDepositShopName(depositShop.getName()); |
| | | vo.setDepositShopPhone(depositShop.getLinkPhone()); |
| | | } |
| | | } |
| | | |
| | | // 取件门店信息 |
| | | if (order.getTakeShopId() != null) { |
| | | ShopInfo takeShop = shopInfoMapper.selectById(order.getTakeShopId()); |
| | | if (takeShop != null) { |
| | | vo.setTakeShopName(takeShop.getName()); |
| | | vo.setTakeShopAddress(takeShop.getAddress()); |
| | | vo.setTakeShopPhone(takeShop.getLinkPhone()); |
| | | } |
| | | } |
| | | |
| | | // 接单司机信息 |
| | | if (order.getAcceptDriver() != null) { |
| | | DriverInfo driverInfo = driverInfoMapper.selectById(order.getAcceptDriver()); |
| | | if (driverInfo != null) { |
| | | vo.setDriverName(driverInfo.getName()); |
| | | } |
| | | } |
| | | |
| | | // 配送附件图片 |
| | | vo.setDepositImages(getFileUrls(id, Constants.FileType.ORDER_DEPOSIT.getKey(), imgPrefix)); |
| | | vo.setStoreInImages(getFileUrls(id, Constants.FileType.ORDER_TAKE.getKey(), imgPrefix)); |
| | | vo.setDriverTakeImages(getFileUrls(id, Constants.FileType.DRIVER_TAKE.getKey(), imgPrefix)); |
| | | vo.setDriverDoneImages(getFileUrls(id, Constants.FileType.DRIVER_DONE.getKey(), imgPrefix)); |
| | | vo.setStoreOutImages(getFileUrls(id, Constants.FileType.STORE_OUT.getKey(), imgPrefix)); |
| | | // 物品明细 |
| | | vo.setDetailList(buildDetailList(id)); |
| | | Category category = categoryMapper.selectById(order.getGoodType()); |
| | | if(CollectionUtils.isNotEmpty(vo.getDetailList())&&Objects.nonNull(category)){ |
| | | for (OrderItemVO v:vo.getDetailList()) { |
| | | v.setTypeName(category.getName()); |
| | | } |
| | | } |
| | | |
| | | // 取消/退款状态时查询退款记录 |
| | | 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() |
| | | .eq(OrdersRefund::getOrderId, id) |
| | | .eq(OrdersRefund::getDeleted, Constants.ZERO) |
| | | .orderByDesc(OrdersRefund::getCreateTime) |
| | | .last("limit 1")); |
| | | if (ordersRefund != null) { |
| | | vo.setOrdersRefund(ordersRefund); |
| | | // 退款方式:1=平台直接取消 → 返回平台操作人名称 |
| | | if (Constants.equalsInteger(ordersRefund.getType(), Constants.ONE) && ordersRefund.getUserId() != null) { |
| | | // userId 关联 system_user 表,查询操作人名称 |
| | | vo.setPlatformUserName(getPlatformUserName(ordersRefund.getUserId())); |
| | | } |
| | | // 退款方式:2=已存件申请取消 → 返回退款取件图片 (multifile objType=14) |
| | | if (Constants.equalsInteger(ordersRefund.getType(), Constants.TWO)) { |
| | | vo.setRefundTakeImages(getFileUrls(id, Constants.FileType.REFUND_TAKE.getKey(), imgPrefix)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return vo; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public String cancelTips(Integer orderId,Member member){ |
| | | Orders orders = ordersMapper.selectById(orderId); |
| | | if(Objects.isNull(orders)||Constants.equalsInteger(orders.getDeleted(),Constants.ONE)){ |
| | | public OrderDispatchVO findDispatchInfo(Integer id) { |
| | | Orders order = ordersMapper.selectById(id); |
| | | if (Objects.isNull(order)) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | |
| | | Integer totalCancelTimes = Integer.valueOf(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RELEASE_CANCEL_TIMES).getCode()); |
| | | Long cancelTimes = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda() |
| | | .apply(" DATE(cancel_time) = DATE(NOW()) ") |
| | | .eq(Orders::getStatus,Constants.ordersStatus.cancel.getKey()) |
| | | .eq(Orders::getReleaseMemberId,member.getId())); |
| | | //查询取消次数 |
| | | if(totalCancelTimes<=cancelTimes){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"今日订单主动取消次数已超出"+totalCancelTimes+"次,无法取消订单"); |
| | | OrderDispatchVO vo = new OrderDispatchVO(); |
| | | vo.setCode(order.getCode()); |
| | | vo.setPayAmountYuan(order.getPayAmount() != null ? Constants.getFormatMoney(order.getPayAmount()) : 0); |
| | | vo.setType(order.getType()); |
| | | vo.setTypeDesc(order.getType() != null && order.getType() == Constants.ONE ? "异地存取" : "就地存取"); |
| | | vo.setDetailList(buildDetailList(id)); |
| | | |
| | | return vo; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void dispatch(DispatchDTO dto) { |
| | | // 参数校验 |
| | | if (dto == null || dto.getOrderId() == null || dto.getUrgentFee() == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单主键和加急费用不能为空"); |
| | | } |
| | | |
| | | Integer cancelTimeHour = Integer.valueOf(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RELEASE_CANCEL_TIME).getCode()); |
| | | Long hours = DateUtil.getBetweenHours(new Date(),orders.getStartDate()); |
| | | if(hours < cancelTimeHour){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"距离订单开始时间不足"+cancelTimeHour+"小时,无法取消订单"); |
| | | Orders order = ordersMapper.selectById(dto.getOrderId()); |
| | | if (Objects.isNull(order)) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | return "今日还可主动取消"+(totalCancelTimes-cancelTimes)+"次,是否确认取消"; |
| | | |
| | | // 前置条件校验:异地存取 + 已寄存 |
| | | if (!Constants.ONE.equals(order.getType())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅支持异地存取订单派单"); |
| | | } |
| | | if (!Integer.valueOf(Constants.OrderStatus.deposited.getStatus()).equals(order.getStatus())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅已寄存状态订单可派单"); |
| | | } |
| | | |
| | | 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.setOrderStatus(order.getStatus()); |
| | | feeLog.setOptUserType(3); |
| | | feeLog.setOptUserName(optUserName); |
| | | feeLog.setCreateTime(new Date()); |
| | | feeLog.setDeleted(Constants.ZERO); |
| | | orderLogService.create(feeLog); |
| | | |
| | | // 加急费用 元→分 |
| | | long urgentFeeFen = dto.getUrgentFee().multiply(new BigDecimal(100)).longValue(); |
| | | |
| | | // 使用 UpdateWrapper 精确更新,不影响其他字段 |
| | | com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<Orders> updateWrapper = |
| | | new UpdateWrapper<Orders>().lambda() |
| | | .eq(Orders::getId, order.getId()) |
| | | .set(Orders::getIsUrgent, Constants.ONE) |
| | | .set(Orders::getPlatformRewardAmount, urgentFeeFen) |
| | | .set(Orders::getUpdateTime, new Date()); |
| | | |
| | | // 异地寄存且有取件门店时,生成司机核销码 |
| | | if (order.getTakeShopId() != null) { |
| | | String driverVerifyCode = generateVerifyCode(); |
| | | updateWrapper.set(Orders::getDriverVerifyCode, driverVerifyCode); |
| | | } |
| | | |
| | | // 备注 |
| | | if (StringUtils.isNotBlank(dto.getRemark())) { |
| | | updateWrapper.set(Orders::getRemark, dto.getRemark()); |
| | | } |
| | | |
| | | // 指派司机(非必填) |
| | | if (dto.getDriverId() != null) { |
| | | updateWrapper.set(Orders::getAssignDriverId, dto.getDriverId()); |
| | | |
| | | 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.setOrderStatus(order.getStatus()); |
| | | driverLog.setOptUserType(3); |
| | | driverLog.setOptUserName(optUserName); |
| | | driverLog.setCreateTime(new Date()); |
| | | driverLog.setDeleted(Constants.ZERO); |
| | | orderLogService.create(driverLog); |
| | | } |
| | | |
| | | ordersMapper.update(updateWrapper); |
| | | } |
| | | |
| | | private String getCurrentUserName() { |
| | | try { |
| | | com.doumee.core.model.LoginUserInfo user = |
| | | (com.doumee.core.model.LoginUserInfo) org.apache.shiro.SecurityUtils.getSubject().getPrincipal(); |
| | | return user != null ? user.getUsername() : "系统"; |
| | | } catch (Exception e) { |
| | | return "系统"; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 发单方取消订单 |
| | | * @param member |
| | | * 构建订单物品明细列表 |
| | | */ |
| | | @Transactional(rollbackFor = {BusinessException.class,Exception.class}) |
| | | public void releaseCancelOrder(Orders orders,Member member){ |
| | | if(!(Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.wait.getKey()) |
| | | ||Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.waitPay.getKey()) |
| | | || Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.accept.getKey()))){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单状态已流转,无法进行取消"); |
| | | } |
| | | if(!Constants.equalsInteger(orders.getReleaseMemberId(),member.getId())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"非您的订单无法进行该操作"); |
| | | } |
| | | //待支付用餐订单/待接单订单进行取消 |
| | | if(Constants.equalsInteger(orders.getStatus(),Constants.ONE) |
| | | ||Constants.equalsInteger(orders.getStatus(),Constants.ZERO)){ |
| | | if(Constants.equalsInteger(orders.getType(),Constants.TWO)&&Constants.equalsInteger(orders.getStatus(),Constants.ONE)){ |
| | | //退款业务 |
| | | WithdrawalOrders withdrawalOrders = new WithdrawalOrders(); |
| | | withdrawalOrders.setCreateTime(new Date()); |
| | | withdrawalOrders.setDeleted(Constants.ZERO); |
| | | withdrawalOrders.setMemberId(orders.getReleaseMemberId()); |
| | | withdrawalOrders.setAmount(orders.getPayAccount()); |
| | | withdrawalOrders.setStatus(Constants.ZERO); |
| | | withdrawalOrders.setDoneTime(new Date()); |
| | | withdrawalOrders.setType(Constants.ONE); |
| | | withdrawalOrders.setObjId(orders.getId()); |
| | | wxMiniUtilService.wxRefund(withdrawalOrders,orders); |
| | | } |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getStatus,Constants.ordersStatus.cancel.getKey()) |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .set(Orders::getCancelTime,new Date()) |
| | | .set(Orders::getCancelType,Constants.ZERO) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | }else{ |
| | | //判断是否可修改 已取消次数 与 时间限制 |
| | | Integer totalCancelTimes = Integer.valueOf(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RELEASE_CANCEL_TIMES).getCode()); |
| | | Long cancelTimes = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda() |
| | | .apply(" DATE(cancel_time) = DATE(NOW()) ") |
| | | .eq(Orders::getStatus,Constants.ordersStatus.cancel.getKey()) |
| | | .eq(Orders::getReleaseMemberId,orders.getReleaseMemberId())); |
| | | //查询取消次数 |
| | | if(totalCancelTimes<=cancelTimes){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"今日订单主动取消次数已超出"+totalCancelTimes+"次,无法取消订单"); |
| | | } |
| | | |
| | | Integer cancelTimeHour = Integer.valueOf(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RELEASE_CANCEL_TIME).getCode()); |
| | | Long hours = DateUtil.getBetweenHours(new Date(),orders.getStartDate()); |
| | | if(hours < cancelTimeHour){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"距离订单开始时间不足"+cancelTimeHour+"小时,无法取消订单"); |
| | | } |
| | | |
| | | if(Constants.equalsInteger(orders.getType(),Constants.TWO)){ |
| | | //退款业务 |
| | | WithdrawalOrders withdrawalOrders = new WithdrawalOrders(); |
| | | withdrawalOrders.setCreateTime(new Date()); |
| | | withdrawalOrders.setMemberId(orders.getReleaseMemberId()); |
| | | withdrawalOrders.setAmount(orders.getPayAccount()); |
| | | withdrawalOrders.setWxExternalNo("refund_"+orders.getCode()); |
| | | withdrawalOrders.setStatus(Constants.ONE); |
| | | withdrawalOrders.setDoneTime(new Date()); |
| | | withdrawalOrders.setType(Constants.ONE); |
| | | withdrawalOrders.setObjId(orders.getId()); |
| | | wxMiniUtilService.wxRefund(withdrawalOrders,orders); |
| | | } |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getStatus,Constants.ordersStatus.cancel.getKey()) |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .set(Orders::getCancelTime,new Date()) |
| | | .set(Orders::getCancelType,Constants.ONE) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | //减少接单量 |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda().setSql("receive_num = (receive_num - 1) ").eq(Member::getId,orders.getAcceptMemberId())); |
| | | } |
| | | //减少发单量 |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda().setSql("publish_num = (publish_num - 1)").eq(Member::getId,orders.getReleaseMemberId())); |
| | | |
| | | //日志存储 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.RELEASE_CANCEL; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),member.getId(),null); |
| | | |
| | | List<Member> members = memberMapper.selectList(new QueryWrapper<Member>().lambda() |
| | | .and(i->i.eq(Member::getId,orders.getReleaseMemberId()).or().eq(Member::getId,orders.getAcceptMemberId())) |
| | | ); |
| | | if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(members)){ |
| | | List<String> openIdList = members.stream().map(i->i.getOpenid()).collect(Collectors.toList()); |
| | | //发送微信通知 |
| | | orders.setCancelTime(new Date()); |
| | | sendWxMessage.cancelMessage(openIdList,orders,Constants.ONE); |
| | | } |
| | | |
| | | IdentityInfo wokerIdentityInfo = identityInfoMapper.selectOne(new QueryWrapper<IdentityInfo>().lambda() |
| | | .eq(IdentityInfo::getMemberId,orders.getAcceptMemberId()) |
| | | .eq(IdentityInfo::getType,orders.getType()) |
| | | .eq(IdentityInfo::getAuditStatus,Constants.TWO) |
| | | .last("limit 1") |
| | | ); |
| | | if(Objects.nonNull(wokerIdentityInfo)){ |
| | | //短信通知 |
| | | aliSmsService.businessSendSms(Constants.smsContent.releaseCancel.getKey(),wokerIdentityInfo.getTelephone(),orders,null, |
| | | null,categoryMapper); |
| | | } |
| | | private List<OrderItemVO> buildDetailList(Integer orderId) { |
| | | List<OrdersDetail> details = ordersDetailMapper.selectList( |
| | | new QueryWrapper<OrdersDetail>().lambda() |
| | | .eq(OrdersDetail::getOrderId, orderId) |
| | | .eq(OrdersDetail::getDeleted, Constants.ZERO)); |
| | | return buildDetailList(details); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 接单方取消接单 |
| | | * @param member |
| | | * 根据已查询的明细构建物品列表(避免重复查询) |
| | | */ |
| | | @Transactional(rollbackFor = {BusinessException.class,Exception.class}) |
| | | public void receiveCancelOrder(Orders orders,Member member){ |
| | | if(!Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.accept.getKey())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单状态已流转,无法进行取消"); |
| | | private List<OrderItemVO> buildDetailList(List<OrdersDetail> details) { |
| | | List<OrderItemVO> items = new ArrayList<>(); |
| | | if (details != null) { |
| | | for (OrdersDetail d : details) { |
| | | OrderItemVO item = new OrderItemVO(); |
| | | item.setLuggageName(d.getLuggageName()); |
| | | item.setLuggageDetail(d.getLuggageDetail()); |
| | | item.setNum(d.getNum()); |
| | | double unitPriceYuan = d.getUnitPrice() != null ? Constants.getFormatMoney(d.getUnitPrice()) : 0; |
| | | item.setUnitPriceYuan(unitPriceYuan); |
| | | item.setSubtotal(unitPriceYuan * (d.getNum() != null ? d.getNum() : 0)); |
| | | items.add(item); |
| | | } |
| | | } |
| | | if(!Constants.equalsInteger(orders.getAcceptMemberId(),member.getId())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"非您的订单无法进行该操作"); |
| | | } |
| | | //判断是否可修改 已取消次数 与 时间限制 |
| | | Integer totalCancelTimes = Integer.valueOf(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RECEIVE_CANCEL_TIMES).getCode()); |
| | | Long cancelTimes = orderLogMapper.selectCount(new QueryWrapper<OrderLog>().lambda() |
| | | .apply(" DATE(create_time) = DATE(NOW()) ") |
| | | .eq(OrderLog::getObjType,Constants.OrdersLog.CANCEL.getKey()) |
| | | .eq(OrderLog::getMemberId,member.getId())); |
| | | //查询取消次数 |
| | | if(totalCancelTimes<=cancelTimes){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"今日订单主动取消次数已超出"+totalCancelTimes+"次,无法取消订单"); |
| | | } |
| | | |
| | | Integer cancelTimeHour = Integer.valueOf(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RECEIVE_CANCEL_TIME).getCode()); |
| | | Long hours = DateUtil.getBetweenHours(new Date(),orders.getStartDate()); |
| | | if(hours < cancelTimeHour){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"距离订单开始时间不足"+cancelTimeHour+"小时,无法取消订单"); |
| | | } |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .set(Orders::getCancelTime,new Date()) |
| | | .set(Orders::getStatus,Constants.ordersStatus.wait.getKey()) |
| | | .set(Orders::getAcceptMemberId,null) |
| | | .set(Orders::getAcceptType,null) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | |
| | | //减少接单量 |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda().setSql(" receive_num = receive_num - 1 ").eq(Member::getId,orders.getAcceptMemberId())); |
| | | //日志存储 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.CANCEL; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),member.getId(),null); |
| | | |
| | | |
| | | List<Member> members = memberMapper.selectList(new QueryWrapper<Member>().lambda() |
| | | .and(i->i.eq(Member::getId,orders.getReleaseMemberId()).or().eq(Member::getId,orders.getAcceptMemberId())) |
| | | ); |
| | | if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(members)){ |
| | | List<String> openIdList = members.stream().map(i->i.getOpenid()).collect(Collectors.toList()); |
| | | //发送微信通知 |
| | | orders.setCancelTime(new Date()); |
| | | sendWxMessage.cancelMessage(openIdList,orders,Constants.TWO); |
| | | } |
| | | //短信通知 |
| | | aliSmsService.businessSendSms(Constants.smsContent.receiveCancel.getKey(),member.getTelephone(),orders,null, |
| | | null,categoryMapper); |
| | | return items; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 完成订单 |
| | | * @param doneOrderDTO |
| | | * 生成32位唯一第三方订单编号(时间戳17位 + 随机数15位) |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = {BusinessException.class,Exception.class}) |
| | | public OrderReleaseVO doneOrder(DoneOrderDTO doneOrderDTO){ |
| | | if(Objects.isNull(doneOrderDTO)||Objects.isNull(doneOrderDTO.getOrderId())){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | Orders orders = ordersMapper.selectById(doneOrderDTO.getOrderId()); |
| | | if(!Constants.equalsInteger(orders.getType(),Constants.TWO)&&Objects.isNull(doneOrderDTO.getAmount())){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | if(Objects.isNull(orders)||Constants.equalsInteger(orders.getDeleted(),Constants.ONE)){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | if(Constants.equalsInteger(orders.getType(),Constants.orderType.scd.getKey())){ |
| | | if(!Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.doing.getKey())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单状态已流转,无法进行取消"); |
| | | } |
| | | }else{ |
| | | if(!Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.feeconfirm.getKey())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单状态已流转,无法进行取消"); |
| | | } |
| | | } |
| | | |
| | | if(!Constants.equalsInteger(orders.getReleaseMemberId(),doneOrderDTO.getMember().getId())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"非您的订单无法进行该操作"); |
| | | } |
| | | Member payMember = memberMapper.selectById(doneOrderDTO.getMember().getId()); |
| | | if(Objects.isNull(payMember)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"用户信息异常"); |
| | | } |
| | | |
| | | OrderReleaseVO orderReleaseVO = new OrderReleaseVO(); |
| | | orderReleaseVO.setId(orders.getId()); |
| | | Object object = null; |
| | | //用餐订单 |
| | | if(!Constants.equalsInteger(orders.getType(),Constants.TWO)){ |
| | | orders.setPayAccount(doneOrderDTO.getAmount()); |
| | | //提成金额 |
| | | // Long tcje = (new BigDecimal(orders.getPayAccount().toString()).multiply(Constants.formatBigDecimal(orders.getPlatformRata())).setScale(0,RoundingMode.HALF_UP).longValue()); |
| | | Long tcje = Long.valueOf(new BigDecimal(orders.getPayAccount().toString()).multiply(orders.getPlatformRata()).intValue()); |
| | | orders.setReceiveAccount(orders.getPayAccount() - tcje); |
| | | orders.setOutTradeNo(UUID.randomUUID().toString().replace("-","")); |
| | | ordersMapper.updateById(orders); |
| | | //唤起支付业务 |
| | | object = this.getWxPayResponse(orders,payMember.getOpenid()); |
| | | orderReleaseVO.setObject(object); |
| | | }else{ |
| | | orders.setStatus(Constants.ordersStatus.done.getKey()); |
| | | orders.setFinishTime(new Date()); |
| | | ordersMapper.updateById(orders); |
| | | |
| | | Member member = memberMapper.selectById(orders.getAcceptMemberId()); |
| | | |
| | | //存储流水记录 |
| | | MemberRevenue memberRevenue = new MemberRevenue(); |
| | | memberRevenue.setCreateTime(new Date()); |
| | | memberRevenue.setMemberId(orders.getAcceptMemberId()); |
| | | memberRevenue.setType(orders.getType()); |
| | | memberRevenue.setOptType(Constants.ONE); |
| | | memberRevenue.setBeforeAmount(member.getAmount()); |
| | | memberRevenue.setAmount(orders.getReceiveAccount()); |
| | | memberRevenue.setAfterAmount(member.getAmount() + orders.getReceiveAccount()); |
| | | if(Constants.equalsInteger(orders.getType(),Constants.ZERO)){ |
| | | memberRevenue.setRemark(Constants.RevenueType.getInfo(memberRevenue.getType()) + "-" + |
| | | (Constants.equalsInteger(orders.getWorkType(),Constants.ZERO)?"采摘工":(Constants.equalsInteger(orders.getWorkType(),Constants.ONE)?"分拣工":"包装工"))); |
| | | }else{ |
| | | memberRevenue.setRemark(Constants.RevenueType.getInfo(memberRevenue.getType())); |
| | | } |
| | | memberRevenue.setObjId(orders.getId()); |
| | | memberRevenue.setObjType(Constants.ZERO); |
| | | memberRevenue.setStatus(Constants.ZERO); |
| | | memberRevenueMapper.insert(memberRevenue); |
| | | |
| | | //日志存储 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.DONE; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),doneOrderDTO.getMember().getId(),null); |
| | | |
| | | sendWxMessage.revenueMessage(member.getOpenid(),orders); |
| | | |
| | | //短信通知接单方 |
| | | if(Objects.nonNull(orders.getAcceptMemberId())){ |
| | | IdentityInfo wokerIdentityInfo = identityInfoMapper.selectOne(new QueryWrapper<IdentityInfo>().lambda() |
| | | .eq(IdentityInfo::getMemberId,orders.getAcceptMemberId()) |
| | | .eq(IdentityInfo::getType,orders.getType()) |
| | | .eq(IdentityInfo::getAuditStatus,Constants.TWO) |
| | | .last("limit 1") |
| | | ); |
| | | if(Objects.nonNull(wokerIdentityInfo)){ |
| | | aliSmsService.businessSendSms(Constants.smsContent.pay.getKey(),wokerIdentityInfo.getTelephone(),orders,null, |
| | | null,categoryMapper); |
| | | } |
| | | } |
| | | } |
| | | return orderReleaseVO; |
| | | private String generateOrderTradeNo() { |
| | | return new java.text.SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) |
| | | + String.format("%015d", Math.abs(new java.util.Random().nextLong() % 1000000000000000L)); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public OrderReleaseVO reusePay(ReusePayDTO reusePayDTO){ |
| | | if(Objects.isNull(reusePayDTO)||Objects.isNull(reusePayDTO.getOrderId())){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | Orders orders = ordersMapper.selectById(reusePayDTO.getOrderId()); |
| | | if(Objects.isNull(orders)||Constants.equalsInteger(orders.getDeleted(),Constants.ONE)){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | if(!Constants.equalsInteger(orders.getType(),Constants.TWO)&&Objects.isNull(reusePayDTO.getAmount())){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | |
| | | if(!((( Constants.equalsInteger(orders.getType(),Constants.TWO) && Constants.equalsInteger(orders.getStatus(),Constants.ZERO) ) |
| | | || ( !Constants.equalsInteger(orders.getType(),Constants.TWO) && Constants.equalsInteger(orders.getStatus(),Constants.FIVE) )) |
| | | && Constants.equalsInteger(orders.getPayStatus(),Constants.ZERO) )){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单状态已流转"); |
| | | } |
| | | Member payMember = memberMapper.selectById(reusePayDTO.getMember().getId()); |
| | | if(Objects.isNull(payMember)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"用户信息异常"); |
| | | } |
| | | |
| | | OrderReleaseVO orderReleaseVO = new OrderReleaseVO(); |
| | | if(!Constants.equalsInteger(orders.getType(),Constants.TWO)){ |
| | | orders.setPayAccount(reusePayDTO.getAmount()); |
| | | //提成金额 |
| | | Long tcje = Long.valueOf(new BigDecimal(orders.getPayAccount().toString()).multiply(orders.getPlatformRata()).intValue()); |
| | | orders.setReceiveAccount(orders.getPayAccount() - tcje); |
| | | orders.setOutTradeNo(UUID.randomUUID().toString().replace("-","")); |
| | | ordersMapper.updateById(orders); |
| | | } |
| | | orders.setOutTradeNo(UUID.randomUUID().toString().replace("-","")); |
| | | ordersMapper.updateById(orders); |
| | | //唤起支付业务 |
| | | Object object = this.getWxPayResponse(orders,payMember.getOpenid()); |
| | | orderReleaseVO.setObject(object); |
| | | orderReleaseVO.setId(orders.getId()); |
| | | return orderReleaseVO; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {BusinessException.class,Exception.class}) |
| | | public void platformCancel(Integer orderId, LoginUserInfo loginUserInfo){ |
| | | Orders orders = ordersMapper.selectById(orderId); |
| | | if(Objects.isNull(orders)||Constants.equalsInteger(orders.getDeleted(),Constants.ONE)){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | if(!(Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.wait.getKey())||Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.accept.getKey()) |
| | | ||Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.doing.getKey())||Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.waitPay.getKey()))){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单状态已流转,无法进行取消"); |
| | | } |
| | | //如果已支付 则需要进行退款 |
| | | if(Constants.equalsInteger(orders.getPayStatus(),Constants.ONE)){ |
| | | WithdrawalOrders withdrawalOrders = new WithdrawalOrders(); |
| | | withdrawalOrders.setCreateTime(new Date()); |
| | | withdrawalOrders.setMemberId(orders.getReleaseMemberId()); |
| | | withdrawalOrders.setAmount(orders.getPayAccount()); |
| | | withdrawalOrders.setWxExternalNo("refund_"+orders.getCode()); |
| | | withdrawalOrders.setStatus(Constants.ONE); |
| | | withdrawalOrders.setDoneTime(new Date()); |
| | | withdrawalOrders.setType(Constants.ONE); |
| | | withdrawalOrders.setObjId(orders.getId()); |
| | | wxMiniUtilService.wxRefund(withdrawalOrders,orders); |
| | | } |
| | | |
| | | //减少发单量 |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda() |
| | | .setSql("publish_num = ifnull(publish_num,0) - 1") |
| | | .eq(Member::getId,orders.getReleaseMemberId())); |
| | | |
| | | if(Constants.equalsInteger(orders.getStatus(),Constants.TWO)||Constants.equalsInteger(orders.getStatus(),Constants.THREE)){ |
| | | //减少接单量 |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda() |
| | | .setSql("receive_num = ifnull(receive_num,0) - 1") |
| | | .eq(Member::getId,orders.getAcceptMemberId())); |
| | | } |
| | | Date date = new Date(); |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getStatus,Constants.ordersStatus.cancel.getKey()) |
| | | .set(Orders::getUpdateTime,date) |
| | | .set(Orders::getCancelTime,date) |
| | | .set(Orders::getCancelType,Constants.TWO) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | |
| | | //日志存储 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.SYSTEM_CANCEL; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),null,loginUserInfo.getId()); |
| | | |
| | | List<Member> members = memberMapper.selectList(new QueryWrapper<Member>().lambda() |
| | | .and(i->i.eq(Member::getId,orders.getReleaseMemberId()).or().eq(Member::getId,orders.getAcceptMemberId())) |
| | | ); |
| | | if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(members)){ |
| | | List<String> openIdList = members.stream().map(i->i.getOpenid()).collect(Collectors.toList()); |
| | | orders.setCancelTime(new Date()); |
| | | //发送微信通知 |
| | | orders.setCancelTime(new Date()); |
| | | sendWxMessage.cancelMessage(openIdList,orders,Constants.ZERO); |
| | | } |
| | | //短信通知发单方 |
| | | aliSmsService.businessSendSms(Constants.smsContent.platformCancel.getKey(),orders.getLinkPhone(),orders,null, |
| | | null,categoryMapper); |
| | | //短信通知接单方 |
| | | if(Objects.nonNull(orders.getAcceptMemberId())){ |
| | | IdentityInfo wokerIdentityInfo = identityInfoMapper.selectOne(new QueryWrapper<IdentityInfo>().lambda() |
| | | .eq(IdentityInfo::getMemberId,orders.getAcceptMemberId()) |
| | | .eq(IdentityInfo::getType,orders.getType()) |
| | | .eq(IdentityInfo::getAuditStatus,Constants.TWO) |
| | | .last("limit 1") |
| | | ); |
| | | if(Objects.nonNull(wokerIdentityInfo)){ |
| | | aliSmsService.businessSendSms(Constants.smsContent.platformCancel2.getKey(),wokerIdentityInfo.getTelephone(),orders,null, |
| | | null,categoryMapper); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void comment(CommentDTO commentDTO){ |
| | | if(Objects.isNull(commentDTO) |
| | | || Objects.isNull(commentDTO.getOrderId()) |
| | | || Objects.isNull(commentDTO.getLevel()) |
| | | || commentDTO.getLevel()<1 || commentDTO.getLevel() > 5 ){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | Orders orders = ordersMapper.selectById(commentDTO.getOrderId()); |
| | | if(Objects.isNull(orders) |
| | | ||Constants.equalsInteger(orders.getDeleted(),Constants.ONE)){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | if(!Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.done.getKey())){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单状态已流转,无法进行评价"); |
| | | } |
| | | if(Constants.equalsInteger(orders.getCommentStatus(),Constants.ONE)){ |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"订单已评价!"); |
| | | } |
| | | |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getCommentStatus,Constants.ONE) |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .set(Orders::getCommentTime,new Date()) |
| | | .set(Orders::getCommentLevel,commentDTO.getLevel()) |
| | | .set(org.apache.commons.lang3.StringUtils.isNotBlank(commentDTO.getInfo()),Orders::getCommentInfo,commentDTO.getInfo()) |
| | | .set(Orders::getCommentType,Constants.ZERO) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda() |
| | | .setSql(" score = ( ifnull(total_score,0) +" + commentDTO.getLevel() + " ) / (ifnull(score_order_num,0) + 1 )") |
| | | .setSql(" total_score = ifnull(total_score,0) +" + commentDTO.getLevel()) |
| | | .setSql(" score_order_num = ifnull(score_order_num,0) + 1 " ) |
| | | .eq(Member::getId,orders.getAcceptMemberId()) |
| | | ); |
| | | //日志存储 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.COMMENT; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),orders.getAcceptMemberId(),null); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 支付回调 |
| | | * @param preOrderId |
| | | * @param paymentNo |
| | | * @return |
| | | * 生成6位数字核销码(Redis验重) |
| | | * 使用 SETNX 抢占,保证唯一;使用完毕后调用 releaseVerifyCode 从 Redis 移除 |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = {BusinessException.class,Exception.class}) |
| | | public String payNotify(String preOrderId,String paymentNo){ |
| | | Orders orders = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda().eq(Orders::getOutTradeNo,preOrderId).last("limit 1")); |
| | | if(Constants.equalsInteger(orders.getType(),Constants.TWO)){ |
| | | //用餐订单 如果已经流转到已支付 则直接返回 |
| | | if(!Constants.equalsInteger(orders.getStatus(),Constants.ZERO)){ |
| | | return ("处理成功!"); |
| | | }else{ |
| | | //处理支付完成逻辑 |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .set(Orders::getStatus,Constants.ordersStatus.wait.getKey()) |
| | | .set(Orders::getPayStatus,Constants.ONE) |
| | | .set(Orders::getPayTime,new Date()) |
| | | .set(Orders::getPayMethod,Constants.ZERO) |
| | | .set(Orders::getWxExternalNo,paymentNo) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | |
| | | //存储日志 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.PAY; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),orders.getReleaseMemberId(),null); |
| | | } |
| | | }else{ |
| | | //非用餐类订单 |
| | | if(!Constants.equalsInteger(orders.getStatus(),Constants.FIVE)){ |
| | | return ("处理成功!"); |
| | | }else{ |
| | | //处理支付完成逻辑 |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .set(Orders::getStatus,Constants.FOUR) |
| | | .set(Orders::getPayStatus,Constants.ONE) |
| | | .set(Orders::getPayTime,new Date()) |
| | | .set(Orders::getPayMethod,Constants.ZERO) |
| | | .set(Orders::getWxExternalNo,paymentNo) |
| | | .set(Orders::getFinishTime,new Date()) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | |
| | | Member member = memberMapper.selectById(orders.getAcceptMemberId()); |
| | | //存储流水记录 |
| | | MemberRevenue memberRevenue = new MemberRevenue(); |
| | | memberRevenue.setCreateTime(new Date()); |
| | | memberRevenue.setDeleted(Constants.ZERO); |
| | | memberRevenue.setTransactionNo(orders.getCode()); |
| | | memberRevenue.setMemberId(orders.getAcceptMemberId()); |
| | | memberRevenue.setType(orders.getType()); |
| | | memberRevenue.setOptType(Constants.ONE); |
| | | memberRevenue.setBeforeAmount(member.getAmount()); |
| | | memberRevenue.setAmount(orders.getReceiveAccount()); |
| | | memberRevenue.setAfterAmount(member.getAmount() + orders.getReceiveAccount()); |
| | | if(Constants.equalsInteger(orders.getType(),Constants.ZERO)){ |
| | | memberRevenue.setRemark(Constants.RevenueType.getInfo(memberRevenue.getType()) + "-" + |
| | | (Constants.equalsInteger(orders.getWorkType(),Constants.ZERO)?"采摘工":(Constants.equalsInteger(orders.getWorkType(),Constants.ONE)?"分拣工":"包装工"))); |
| | | }else{ |
| | | memberRevenue.setRemark(Constants.RevenueType.getInfo(memberRevenue.getType())); |
| | | } |
| | | memberRevenue.setObjId(orders.getId()); |
| | | memberRevenue.setObjType(Constants.ZERO); |
| | | memberRevenue.setStatus(Constants.ZERO); |
| | | memberRevenueMapper.insert(memberRevenue); |
| | | |
| | | //更新接单用户的余额与历史总金额 |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda() |
| | | .setSql(" amount = ( amount + " + orders.getReceiveAccount() +")" ) |
| | | .setSql(" total_amount = ( amount + " + orders.getReceiveAccount() + ")" ) |
| | | .eq(Member::getId,member.getId()) |
| | | ); |
| | | |
| | | //存储日志 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.PAY; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),orders.getReleaseMemberId(),null); |
| | | |
| | | // 通知接单方 款项已到账 |
| | | sendWxMessage.revenueMessage(member.getOpenid(),orders); |
| | | |
| | | //短信通知接单方 |
| | | if(Objects.nonNull(orders.getAcceptMemberId())){ |
| | | IdentityInfo wokerIdentityInfo = identityInfoMapper.selectOne(new QueryWrapper<IdentityInfo>().lambda() |
| | | .eq(IdentityInfo::getMemberId,orders.getAcceptMemberId()) |
| | | .eq(IdentityInfo::getType,orders.getType()) |
| | | .eq(IdentityInfo::getAuditStatus,Constants.TWO) |
| | | .last("limit 1") |
| | | ); |
| | | if(Objects.nonNull(wokerIdentityInfo)){ |
| | | aliSmsService.businessSendSms(Constants.smsContent.pay.getKey(),wokerIdentityInfo.getTelephone(),orders,null, |
| | | null,categoryMapper); |
| | | } |
| | | } |
| | | |
| | | private String generateVerifyCode() { |
| | | Random random = new Random(); |
| | | String redisKey = Constants.REDIS_VERIFY_CODE_KEY; |
| | | for (int i = 0; i < 200; i++) { |
| | | String code = String.format("%06d", random.nextInt(1000000)); |
| | | Boolean success = redisTemplate.opsForValue().setIfAbsent(redisKey + code, "1", 24, TimeUnit.HOURS); |
| | | if (success != null && success) { |
| | | return code; |
| | | } |
| | | } |
| | | return ("处理成功!"); |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "核销码生成失败,请重试"); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public PageData<Orders> findPageForMini(PageWrap<Orders> pageWrap) { |
| | | IPage<Orders> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); |
| | | MPJLambdaWrapper<Orders> queryWrapper = new MPJLambdaWrapper<>(); |
| | | Utils.MP.blankToNull(pageWrap.getModel()); |
| | | Orders model = pageWrap.getModel(); |
| | | if(Objects.isNull(model) |
| | | || Objects.isNull(model.getQueryMyOrderType()) |
| | | ){ |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST); |
| | | } |
| | | BigDecimal chefLat = model.getQueryLat(); |
| | | BigDecimal chefLgt = model.getQueryLgt(); |
| | | BigDecimal driverLat = model.getQueryLat(); |
| | | BigDecimal driverLgt = model.getQueryLgt(); |
| | | BigDecimal workerLat = model.getQueryLat(); |
| | | BigDecimal workerLgt = model.getQueryLgt(); |
| | | IdentityInfo wokerIdentityInfo = identityInfoMapper.selectOne(new QueryWrapper<IdentityInfo>().lambda() |
| | | .eq(IdentityInfo::getMemberId,model.getMember().getId()) |
| | | .eq(IdentityInfo::getType,Constants.ZERO) |
| | | .eq(IdentityInfo::getAuditStatus,Constants.TWO) |
| | | .last("limit 1") |
| | | ); |
| | | if(Objects.nonNull(wokerIdentityInfo)){ |
| | | workerLat = wokerIdentityInfo.getLat(); |
| | | workerLgt = wokerIdentityInfo.getLgt(); |
| | | } |
| | | IdentityInfo driverIdentityInfo = identityInfoMapper.selectOne(new QueryWrapper<IdentityInfo>().lambda() |
| | | .eq(IdentityInfo::getMemberId,model.getMember().getId()) |
| | | .eq(IdentityInfo::getType,Constants.ONE) |
| | | .eq(IdentityInfo::getAuditStatus,Constants.TWO) |
| | | .last("limit 1") |
| | | ); |
| | | if(Objects.nonNull(driverIdentityInfo)){ |
| | | driverLat = driverIdentityInfo.getLat(); |
| | | driverLgt = driverIdentityInfo.getLgt(); |
| | | } |
| | | IdentityInfo chefIdentityInfo = identityInfoMapper.selectOne(new QueryWrapper<IdentityInfo>().lambda() |
| | | .eq(IdentityInfo::getMemberId,model.getMember().getId()) |
| | | .eq(IdentityInfo::getType,Constants.TWO) |
| | | .eq(IdentityInfo::getAuditStatus,Constants.TWO) |
| | | .last("limit 1") |
| | | ); |
| | | if(Objects.nonNull(chefIdentityInfo)){ |
| | | chefLat = chefIdentityInfo.getLat(); |
| | | chefLgt = chefIdentityInfo.getLgt(); |
| | | } |
| | | queryWrapper.selectAll(Orders.class) |
| | | .select("c1.name",Orders::getCategoryName) |
| | | .select("c2.name",Orders::getTransportTypeName) |
| | | .leftJoin(" category c1 on t.category_id = c1.id ") |
| | | .leftJoin(" category c2 on t.TRANSPORT_TYPE_ID = c2.id ") |
| | | .eq(Objects.nonNull(model.getType()),Orders::getType,model.getType()) |
| | | .eq(Objects.nonNull(model.getCommentStatus()),Orders::getCommentStatus,model.getCommentStatus());; |
| | | if(!(Objects.isNull(model.getQueryLat())||Objects.isNull(model.getQueryLgt()))){ |
| | | queryWrapper.select(" case when T.LGT IS NULL OR T.LAT IS NULL THEN 0 " + |
| | | " when t.TYPE = 0 then CONVERT( ST_Distance_Sphere ( POINT ( t.LGT, t.LAT ), POINT ( "+workerLgt+", "+workerLat+" )) /1000,DECIMAL(15,2)) " + |
| | | " when t.TYPE = 1 then CONVERT( ST_Distance_Sphere ( POINT ( t.LGT, t.LAT ), POINT ( "+driverLgt+", "+driverLat+" )) /1000,DECIMAL(15,2)) " + |
| | | " else CONVERT( ST_Distance_Sphere ( POINT ( t.LGT, t.LAT ), POINT ( "+chefLgt+", "+chefLat+" )) /1000,DECIMAL(15,2)) end " , Orders::getDistance); |
| | | } |
| | | if(Objects.nonNull(model.getQueryMyOrderType())){ |
| | | if(Constants.equalsInteger(model.getQueryMyOrderType(),Constants.ZERO)){ |
| | | //发单方 我的订单 |
| | | queryWrapper.eq(Orders::getReleaseMemberId,model.getMember().getId()); |
| | | queryWrapper.eq(Objects.nonNull(model.getStatus())&&!Constants.equalsInteger(model.getStatus(),Constants.ordersStatus.waitPay.getKey()),Orders::getStatus,model.getStatus()); |
| | | queryWrapper.in(Objects.nonNull(model.getStatus())&&Constants.equalsInteger(model.getStatus(),Constants.ordersStatus.waitPay.getKey()),Orders::getStatus,model.getStatus(),Constants.ordersStatus.feeconfirm.getKey()); |
| | | queryWrapper.orderByDesc(Orders::getCreateTime); |
| | | }else if(Constants.equalsInteger(model.getQueryMyOrderType(),Constants.ONE)){ |
| | | //接单方 我的订单 |
| | | queryWrapper.eq(Orders::getAcceptMemberId,model.getMember().getId()); |
| | | queryWrapper.eq(Objects.nonNull(model.getStatus()),Orders::getStatus,model.getStatus()); |
| | | // queryWrapper.in(Objects.nonNull(model.getStatus())&&Constants.equalsInteger(model.getStatus(),Constants.ordersStatus.waitPay.getKey()),Orders::getStatus,model.getStatus(),Constants.ordersStatus.feeconfirm.getKey()); |
| | | queryWrapper.orderByDesc(Orders::getAcceptTime); |
| | | }else{ |
| | | //查询用户的接单权重 接单大厅 |
| | | ReceiveWeight receiveWeight = receiveWeightMapper.selectOne(new QueryWrapper<ReceiveWeight>().lambda().eq(ReceiveWeight::getDeleted,Constants.ZERO).apply(" RECEIVE_MIN < "+model.getMember().getReceiveNum()+" and RECEIVE_MAX > " + model.getMember().getReceiveNum()).last(" limit 1 ")); |
| | | if(Objects.nonNull(receiveWeight)){ |
| | | queryWrapper.apply(" DATE_ADD(t.CREATE_TIME, INTERVAL "+receiveWeight.getDelayTime()+" MINUTE) < now() "); |
| | | } |
| | | queryWrapper.eq(Orders::getStatus,Constants.ordersStatus.wait.getKey()); |
| | | queryWrapper.ne(Orders::getReleaseMemberId,model.getMember().getId()); |
| | | if(Objects.nonNull(model.getSortType())){ |
| | | if(Constants.equalsInteger(model.getSortType(),Constants.ZERO)){ |
| | | queryWrapper.orderByDesc(Orders::getCreateTime); |
| | | }else if(Constants.equalsInteger(model.getSortType(),Constants.ONE)){ |
| | | queryWrapper.orderByAsc(" distance "); |
| | | }else{ |
| | | queryWrapper.orderByDesc(Orders::getEstimatedAccount); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | IPage<Orders> iPage = ordersMapper.selectJoinPage(page,Orders.class,queryWrapper); |
| | | for (Orders orders:iPage.getRecords()) { |
| | | this.getPriceUnit(orders); |
| | | if(Constants.equalsInteger(model.getQueryMyOrderType(),Constants.ZERO)||Constants.equalsInteger(model.getQueryMyOrderType(),Constants.ONE)){ |
| | | orders.setStatusName( |
| | | Constants.equalsInteger(model.getQueryMyOrderType(),Constants.ZERO)?Constants.ordersStatus.getName(orders.getStatus()): |
| | | Constants.ordersStatus.getInfo(orders.getStatus()) |
| | | ); |
| | | } |
| | | } |
| | | return PageData.from(iPage); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | //定位距离 |
| | | public void getDistance(Member member,Orders orders){ |
| | | try{ |
| | | if(Constants.equalsInteger(orders.getType(),Constants.ZERO)){ |
| | | if(Objects.nonNull(member.getWorkerIdentityModel())&&Objects.nonNull(member.getWorkerIdentityModel().getLgt()) |
| | | &&Objects.nonNull(member.getWorkerIdentityModel().getLat())){ |
| | | orders.setDistance( |
| | | GeoUtils.haversineDistance( |
| | | orders.getLgt().doubleValue(),orders.getLat().doubleValue(), |
| | | member.getWorkerIdentityModel().getLgt().doubleValue(), |
| | | member.getWorkerIdentityModel().getLat().doubleValue() |
| | | ) |
| | | ); |
| | | } |
| | | |
| | | }else if(Constants.equalsInteger(orders.getType(),Constants.ONE)){ |
| | | if(Objects.nonNull(member.getDriverIdentityModel())&&Objects.nonNull(member.getDriverIdentityModel().getLgt()) |
| | | &&Objects.nonNull(member.getDriverIdentityModel().getLat())) { |
| | | orders.setDistance( |
| | | GeoUtils.haversineDistance( |
| | | orders.getLgt().doubleValue(), orders.getLat().doubleValue(), |
| | | member.getDriverIdentityModel().getLgt().doubleValue(), |
| | | member.getDriverIdentityModel().getLat().doubleValue() |
| | | ) |
| | | ); |
| | | } |
| | | }else{ |
| | | if(Objects.nonNull(member.getChefIdentityModel())&&Objects.nonNull(member.getChefIdentityModel().getLgt()) |
| | | &&Objects.nonNull(member.getChefIdentityModel().getLat())) { |
| | | orders.setDistance( |
| | | GeoUtils.haversineDistance( |
| | | orders.getLgt().doubleValue(),orders.getLat().doubleValue(), |
| | | member.getChefIdentityModel().getLgt().doubleValue(), |
| | | member.getChefIdentityModel().getLat().doubleValue() |
| | | ) |
| | | ); |
| | | } |
| | | } |
| | | }catch (Exception e){ |
| | | orders.setDistance(0L); |
| | | /** |
| | | * 释放核销码占位(核销完成后调用,移除 Redis 中的 key) |
| | | */ |
| | | public void releaseVerifyCode(String code) { |
| | | if (StringUtils.isNotBlank(code)) { |
| | | redisTemplate.delete(Constants.REDIS_VERIFY_CODE_KEY + code); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public Orders getDetail(Integer id,Member member) { |
| | | Orders orders = ordersMapper.selectJoinOne(Orders.class,new MPJLambdaWrapper<Orders>() |
| | | .selectAll(Orders.class) |
| | | .select(" m1.name " , Orders::getReleaseName) |
| | | .select(" m1.telephone " , Orders::getReleasePhone) |
| | | .select(" case when i.AUTH_TYPE = 0 then i.LINK_NAME else i.COMPANY_NAME end " , Orders::getAcceptName) |
| | | .select(" i.TELEPHONE " , Orders::getAcceptPhone) |
| | | .select("c1.name",Orders::getCategoryName) |
| | | .select("c2.name",Orders::getTransportTypeName) |
| | | .select(" m2.SCORE " , Orders::getScore) |
| | | .select(" m1.PUBLISH_NUM " , Orders::getPublishNum) |
| | | .select(" m2.RECEIVE_NUM " , Orders::getReceiveNum) |
| | | .select(" m1.COVER_IMAGE " , Orders::getReleaseCoverImage) |
| | | .select(" m2.COVER_IMAGE " , Orders::getAcceptCoverImage) |
| | | .leftJoin(" category c1 on t.category_id = c1.id ") |
| | | .leftJoin(" category c2 on t.TRANSPORT_TYPE_ID = c2.id ") |
| | | .leftJoin("member m1 on t.RELEASE_MEMBER_ID = m1.id ") |
| | | .leftJoin("member m2 on t.ACCEPT_MEMBER_ID = m2.id ") |
| | | .leftJoin("identity_info i on m2.id = i.MEMBER_ID and i.TYPE = t.type and i.AUDIT_STATUS = 2 ") |
| | | |
| | | .eq(Orders::getId,id) |
| | | ); |
| | | if(Objects.isNull(orders)){ |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | private String getOrdersPrefix() { |
| | | try { |
| | | return systemDictDataBiz.queryByCode(Constants.OSS, Constants.RESOURCE_PATH).getCode() |
| | | + systemDictDataBiz.queryByCode(Constants.OSS, Constants.ORDERS_FILES).getCode(); |
| | | } catch (Exception e) { |
| | | return ""; |
| | | } |
| | | //头像信息 |
| | | String coverPath = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RESOURCE_PATH).getCode() |
| | | +systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.MEMBER_FILES).getCode(); |
| | | if(org.apache.commons.lang3.StringUtils.isNotBlank(orders.getReleaseCoverImage())){ |
| | | orders.setReleaseCoverImage(coverPath + orders.getReleaseCoverImage()); |
| | | } |
| | | if(org.apache.commons.lang3.StringUtils.isNotBlank(orders.getAcceptCoverImage())){ |
| | | orders.setAcceptCoverImage(coverPath + orders.getAcceptCoverImage()); |
| | | } |
| | | List<Multifile> multifileList = multifileMapper.selectList(new QueryWrapper<Multifile>().lambda().eq(Multifile::getObjId,orders.getId()) |
| | | .eq(Multifile::getIsdeleted,Constants.ZERO).eq(Multifile::getObjType,Constants.ONE).orderByAsc(Multifile::getId)); |
| | | if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(multifileList)){ |
| | | String path = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RESOURCE_PATH).getCode() |
| | | +systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.ORDERS_FILES).getCode(); |
| | | for (Multifile multifile:multifileList) { |
| | | multifile.setFileurlFull(path + multifile.getFileurl()); |
| | | } |
| | | orders.setMultifileList(multifileList); |
| | | } |
| | | orders.setStatusName(Constants.ordersStatus.getName(orders.getStatus())); |
| | | orders.setCancelStatus(Constants.ZERO); |
| | | if(Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.accept.getKey())&&Constants.equalsInteger(orders.getIsUpdate(),Constants.ONE)){ |
| | | String autoConfirmTime = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.AUTO_CONFIRM).getCode(); |
| | | orders.setConfirmCountdown(DateUtil.getXMinuteAfterDate(orders.getIsUpdateTime(),Integer.valueOf(autoConfirmTime)).getTime() - System.currentTimeMillis()); |
| | | if(orders.getConfirmCountdown()<=Constants.ZERO){ |
| | | orders.setConfirmCountdown(0L); |
| | | } |
| | | } |
| | | if(Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.waitPay.getKey())){ |
| | | orders.setCancelCountdown(DateUtil.getXMinuteAfterDate(orders.getCreateTime(),15).getTime() - System.currentTimeMillis()); |
| | | if(orders.getCancelCountdown()<=Constants.ZERO){ |
| | | orders.setCancelCountdown(0L); |
| | | } |
| | | } |
| | | this.getPriceUnit(orders); |
| | | orders.setCanStart(Constants.ZERO); |
| | | if(orders.getStatus() <= Constants.ordersStatus.accept.getKey()){ |
| | | if(Constants.equalsInteger(orders.getReleaseMemberId(),member.getId())){ |
| | | if(Constants.equalsInteger(orders.getStatus(),Constants.ordersStatus.accept.getKey())&&orders.getStartDate().getTime() <= System.currentTimeMillis()){ |
| | | orders.setCanStart(Constants.ONE); |
| | | } |
| | | //判断是否可修改 已取消次数 与 时间限制 |
| | | Integer totalCancelTimes = Integer.valueOf(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RELEASE_CANCEL_TIMES).getCode()); |
| | | Long cancelTimes = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda() |
| | | .apply(" DATE(cancel_time) = DATE(NOW()) ") |
| | | .eq(Orders::getStatus,Constants.ordersStatus.cancel.getKey()) |
| | | .eq(Orders::getReleaseMemberId,orders.getReleaseMemberId())); |
| | | //查询取消次数 |
| | | if(totalCancelTimes<=cancelTimes){ |
| | | orders.setCancelStatus(Constants.ONE); |
| | | return orders; |
| | | } |
| | | Integer cancelTimeHour = Integer.valueOf(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RELEASE_CANCEL_TIME).getCode()); |
| | | Long hours = DateUtil.getBetweenHours(new Date(),orders.getStartDate()); |
| | | if(hours < cancelTimeHour){ |
| | | orders.setCancelStatus(Constants.ONE); |
| | | return orders; |
| | | } |
| | | }else if(Constants.equalsInteger(orders.getAcceptMemberId(),member.getId())){ |
| | | //判断是否可修改 已取消次数 与 时间限制 |
| | | Integer totalCancelTimes = Integer.valueOf(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RECEIVE_CANCEL_TIMES).getCode()); |
| | | Long cancelTimes = orderLogMapper.selectCount(new QueryWrapper<OrderLog>().lambda() |
| | | .apply(" DATE(create_time) = DATE(NOW()) ") |
| | | .eq(OrderLog::getObjType,Constants.OrdersLog.CANCEL.getKey()) |
| | | .eq(OrderLog::getMemberId,member.getId())); |
| | | //查询取消次数 |
| | | if(totalCancelTimes<=cancelTimes){ |
| | | orders.setCancelStatus(Constants.ONE); |
| | | return orders; |
| | | } |
| | | |
| | | Integer cancelTimeHour = Integer.valueOf(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RECEIVE_CANCEL_TIME).getCode()); |
| | | Long hours = DateUtil.getBetweenHours(new Date(),orders.getStartDate()); |
| | | if(hours < cancelTimeHour){ |
| | | orders.setCancelStatus(Constants.ONE); |
| | | return orders; |
| | | } |
| | | } |
| | | } else{ |
| | | orders.setCancelStatus(Constants.ONE); |
| | | } |
| | | return orders; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | public synchronized String getNextCode(Integer type){ |
| | | String prefix = "YG"; |
| | | if(!Constants.equalsInteger(type,Constants.ZERO)){ |
| | | prefix = (Constants.equalsInteger(type,Constants.ONE)?"YH-":"DC-"); |
| | | } |
| | | prefix = prefix + DateUtil.getCurrDateTimeShort() +"-"; |
| | | |
| | | Integer countNum = (Integer) redisTemplate.opsForValue().get(Constants.RedisKeys.ORDER_CODE);//RedisUtil.getObject(redisTemplate, Constants.RedisKeys.ORDER_CODE, Integer.class); |
| | | countNum = Constants.formatIntegerNum(countNum)+1; |
| | | //更新缓存 |
| | | redisTemplate.opsForValue().set(Constants.RedisKeys.ORDER_CODE,countNum); |
| | | String nextIndex =Integer.toString( countNum ); |
| | | return prefix + org.apache.commons.lang3.StringUtils.leftPad(nextIndex,3,"0"); |
| | | private String getPlatformUserName(Integer userId) { |
| | | SystemUser user = systemUserMapper.selectById(userId); |
| | | return user != null ? user.getRealname() : null; |
| | | } |
| | | |
| | | private List<String> getFileUrls(Integer orderId, int objType, String prefix) { |
| | | List<Multifile> files = multifileMapper.selectList( |
| | | new QueryWrapper<Multifile>().lambda() |
| | | .eq(Multifile::getObjId, orderId) |
| | | .eq(Multifile::getObjType, objType) |
| | | .eq(Multifile::getIsdeleted, Constants.ZERO) |
| | | .orderByAsc(Multifile::getSortnum)); |
| | | List<String> urls = new ArrayList<>(); |
| | | if (files != null) { |
| | | for (Multifile f : files) { |
| | | if (StringUtils.isNotBlank(f.getFileurl())) { |
| | | urls.add(prefix + f.getFileurl()); |
| | | } |
| | | } |
| | | } |
| | | return urls; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class,BusinessException.class}) |
| | | public void refundCallback(RefundNotification refundNotification){ |
| | | WithdrawalOrders withdrawalOrders = withdrawalOrdersMapper.selectById(refundNotification.getOutRefundNo()); |
| | | if(Objects.isNull(withdrawalOrders)||!Constants.equalsInteger(withdrawalOrders.getStatus(),Constants.ZERO)){ |
| | | /** |
| | | * 计算并设置订单薪酬分配(司机、存件门店、取件门店) |
| | | * 从 pricing_rule (type=4) 读取分成比例,根据门店企业/个人类型区分 |
| | | * |
| | | * @param orders 订单实体(需要 totalAmount、cityId 已设置) |
| | | * @param depositShop 寄件门店(需要 companyType) |
| | | * @param takeShop 取件门店(需要 companyType,就地存取时与 depositShop 相同) |
| | | */ |
| | | private void calculateAndSetFeeAllocation(Orders orders, ShopInfo depositShop, ShopInfo takeShop) { |
| | | Long totalAmount = orders.getTotalAmount() != null ? orders.getTotalAmount() : 0L; |
| | | if (totalAmount <= 0) { |
| | | orders.setDriverFee(0L); |
| | | orders.setDepositShopFee(0L); |
| | | orders.setTakeShopFee(0L); |
| | | orders.setDriverFeeRata(BigDecimal.ZERO); |
| | | orders.setDepositShopFeeRata(BigDecimal.ZERO); |
| | | orders.setTakeShopFeeRata(BigDecimal.ZERO); |
| | | return; |
| | | } |
| | | withdrawalOrders.setWxExternalNo(refundNotification.getTransactionId()); |
| | | withdrawalOrders.setUpdateTime(new Date()); |
| | | withdrawalOrders.setDoneTime(withdrawalOrders.getUpdateTime()); |
| | | if (!"SUCCESS".equals(refundNotification.getRefundStatus().name())) { |
| | | // 如果退款状态不正确,修改退款单状态 |
| | | withdrawalOrders.setStatus(Constants.TWO); |
| | | }else{ |
| | | withdrawalOrders.setStatus(Constants.ONE); |
| | | } |
| | | //更新退款单状态 |
| | | withdrawalOrdersMapper.updateById(withdrawalOrders); |
| | | } |
| | | Integer cityId = Integer.valueOf(orders.getCityId()); |
| | | |
| | | // 司机占比:fieldA=4(配送员) |
| | | BigDecimal driverRata = getRevenueShareRata(cityId, Constants.FOUR); |
| | | // 寄件门店占比:fieldA=0(企业寄)/1(个人寄) |
| | | int depositFieldA = Constants.equalsInteger(depositShop.getCompanyType(), Constants.ONE) ? Constants.ZERO : Constants.ONE; |
| | | BigDecimal depositShopRata = getRevenueShareRata(cityId, depositFieldA); |
| | | // 取件门店占比:fieldA=2(企业取)/3(个人取) |
| | | int takeFieldA = Constants.equalsInteger(takeShop.getCompanyType(), Constants.ONE) ? Constants.TWO : Constants.THREE; |
| | | BigDecimal takeShopRata = getRevenueShareRata(cityId, takeFieldA); |
| | | |
| | | // 计算薪酬(分):totalAmount 为分,rata 为比例值(如 0.15 表示 15%) |
| | | long driverFee = new BigDecimal(totalAmount).multiply(driverRata).longValue(); |
| | | long depositShopFee = new BigDecimal(totalAmount).multiply(depositShopRata).longValue(); |
| | | long takeShopFee = totalAmount - driverFee - depositShopFee; |
| | | |
| | | orders.setDriverFee(driverFee); |
| | | orders.setDepositShopFee(depositShopFee); |
| | | orders.setTakeShopFee(takeShopFee); |
| | | orders.setDriverFeeRata(driverRata); |
| | | orders.setDepositShopFeeRata(depositShopRata); |
| | | orders.setTakeShopFeeRata(takeShopRata); |
| | | } |
| | | |
| | | /** |
| | | * 自动派单 |
| | | * 从 pricing_rule 表获取分成比例(type=4) |
| | | * |
| | | * @param cityId 城市主键 |
| | | * @param fieldA 类型:0=企业寄, 1=个人寄, 2=企业取, 3=个人取, 4=配送员 |
| | | * @return 分成比例(如 0.15 表示 15%) |
| | | */ |
| | | private BigDecimal getRevenueShareRata(Integer cityId, int fieldA) { |
| | | PricingRule rule = pricingRuleMapper.selectOne(new QueryWrapper<PricingRule>().lambda() |
| | | .eq(PricingRule::getDeleted, Constants.ZERO) |
| | | .eq(PricingRule::getType, Constants.FOUR) |
| | | .eq(PricingRule::getCityId, cityId) |
| | | .eq(PricingRule::getFieldA, String.valueOf(fieldA)) |
| | | .last("limit 1")); |
| | | if (rule != null && StringUtils.isNotBlank(rule.getFieldC())) { |
| | | return new BigDecimal(rule.getFieldC()); |
| | | } |
| | | return BigDecimal.ZERO; |
| | | } |
| | | |
| | | @Override |
| | | public void autoGrabOrders(){ |
| | | String autoConfirmTime = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.AUTO_DISPATCH).getCode(); |
| | | List<Orders> ordersList = ordersMapper.selectList(new QueryWrapper<Orders>().lambda().eq(Orders::getDeleted,Constants.ZERO) |
| | | .eq(Orders::getStatus,Constants.ONE).eq(Orders::getCommentStatus,Constants.ZERO) |
| | | .apply(" DATE_ADD(create_time, INTERVAL "+autoConfirmTime+" MINUTE) < now() ") |
| | | .last("limit 100") |
| | | ); |
| | | for (Orders orders:ordersList) { |
| | | BigDecimal lat = orders.getLat(); |
| | | BigDecimal lgt = orders.getLgt(); |
| | | //查询范围内的会员 |
| | | List<Member> memberList = memberMapper.getList(lgt,lat,orders.getType(),orders.getReleaseMemberId()); |
| | | // memberMapper.selectList(new MPJLambdaWrapper<Member>() |
| | | // .select(Member::getId,Member::getScore) |
| | | // .select(" ifnull((select r.level from receive_weight r where r.RECEIVE_MAX > RECEIVE_NUM and RECEIVE_NUM > r.RECEIVE_MIN limit 1 ),0) " ,Member::getLevel) |
| | | // .select( " ifnull( (select CONVERT( ST_Distance_Sphere ( POINT ( ii.lgt, ii.lat ), POINT ( "+lgt+", "+lat+" )) /1000,DECIMAL(15,2)) from identity_info ii where ii.AUDIT_STATUS = 2 and type = 0 and ii.member_id = ID limit 1 ),0) ",Member::getDistance ) |
| | | //// |
| | | // .apply(" id in (" + |
| | | // " select ii.member_id from identity_info ii where ii.AUDIT_STATUS = 2 and type = '"+orders.getType()+"' " + |
| | | // " and ( CONVERT( ST_Distance_Sphere ( POINT ( ii.lgt, ii.lat ), POINT ( "+lgt+", "+lat+" )) /1000,DECIMAL(15,2))) < 100 " + |
| | | // ") ") |
| | | // .orderByDesc(" level , score ") |
| | | // .orderByAsc(Member::getDistance) |
| | | // .last(" limit 1 ") |
| | | // ); |
| | | if(CollectionUtils.isEmpty(memberList)){ |
| | | continue; |
| | | public PageData<MyOrderVO> findMyOrderPage(PageWrap<MyOrderDTO> pageWrap, Integer memberId) { |
| | | MyOrderDTO model = pageWrap.getModel(); |
| | | Integer status = model != null ? model.getStatus() : null; |
| | | Integer combinedStatus = model != null ? model.getCombinedStatus() : null; |
| | | |
| | | // 解析合并状态为具体状态列表 |
| | | List<Integer> statusList = null; |
| | | if (combinedStatus != null) { |
| | | Constants.OrderCombinedStatus combined = Constants.OrderCombinedStatus.getByKey(combinedStatus); |
| | | if (combined != null) { |
| | | statusList = new ArrayList<>(); |
| | | for (int s : combined.getStatuses()) { |
| | | statusList.add(s); |
| | | } |
| | | } |
| | | } |
| | | |
| | | Member member = memberList.get(Constants.ZERO); |
| | | Member releaseMember = memberMapper.selectById(orders.getReleaseMemberId()); |
| | | //自动派单 |
| | | Orders model = ordersMapper.selectById(orders.getId()); |
| | | if(!Constants.equalsInteger(model.getStatus(),Constants.ONE) || Constants.equalsInteger(releaseMember.getId(),model.getReleaseMemberId())){ |
| | | //如果订单已删除 并且非发布方 |
| | | continue; |
| | | IPage<Orders> p = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); |
| | | MPJLambdaWrapper<Orders> wrapper = new MPJLambdaWrapper<Orders>() |
| | | .selectAll(Orders.class) |
| | | .select("s1.name", Orders::getDepositShopName) |
| | | .select("s1.link_name", Orders::getDepositShopLinkName) |
| | | .select("s1.link_phone", Orders::getDepositShopLinkPhone) |
| | | .select("s2.name", Orders::getTakeShopName) |
| | | .select("s2.address", Orders::getTakeShopAddress) |
| | | .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID") |
| | | .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID") |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .eq(Orders::getMemberId, memberId) |
| | | .eq(status != null, Orders::getStatus, status) |
| | | .in(statusList != null, Orders::getStatus, statusList) |
| | | .orderByDesc(Orders::getCreateTime); |
| | | |
| | | IPage<Orders> orderPage = ordersMapper.selectJoinPage(p, Orders.class, wrapper); |
| | | List<MyOrderVO> voList = new ArrayList<>(); |
| | | if (orderPage != null && orderPage.getRecords() != null) { |
| | | |
| | | for (Orders o : orderPage.getRecords()) { |
| | | MyOrderVO vo = new MyOrderVO(); |
| | | vo.setId(o.getId()); |
| | | vo.setCode(o.getCode()); |
| | | vo.setType(o.getType()); |
| | | vo.setStatus(o.getStatus()); |
| | | vo.setCreateTime(o.getCreateTime()); |
| | | vo.setExpectedTakeTime(o.getExpectedTakeTime()); |
| | | |
| | | // 存件门店(关联查询直接取值) |
| | | vo.setDepositShopName(o.getDepositShopName()); |
| | | vo.setDepositShopLinkName(o.getDepositShopLinkName()); |
| | | vo.setDepositShopPhone(o.getDepositShopLinkPhone()); |
| | | |
| | | // 取件信息:有取件门店取门店,无则取用户自选取件点 |
| | | if (o.getTakeShopId() != null) { |
| | | vo.setTakeShopName(o.getTakeShopName()); |
| | | vo.setTakeShopAddress(o.getTakeShopAddress()); |
| | | } else { |
| | | vo.setTakeLocation(o.getTakeLocation()); |
| | | vo.setTakeLocationRemark(o.getTakeLocationRemark()); |
| | | } |
| | | |
| | | // 取件联系人 |
| | | vo.setTakeUser(o.getTakeUser()); |
| | | vo.setTakePhone(o.getTakePhone()); |
| | | |
| | | // 费用(分) |
| | | vo.setDeclaredFee(o.getDeclaredFee()); |
| | | vo.setEstimatedAmount(o.getEstimatedAmount()); |
| | | |
| | | // 查询物品明细(一次查询,同时用于物品列表和逾期计算) |
| | | List<OrdersDetail> details = ordersDetailMapper.selectList( |
| | | new QueryWrapper<OrdersDetail>().lambda() |
| | | .eq(OrdersDetail::getOrderId, o.getId()) |
| | | .eq(OrdersDetail::getDeleted, Constants.ZERO)); |
| | | |
| | | // 物品明细 |
| | | 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()); |
| | | } |
| | | voList.add(vo); |
| | | } |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda().eq(Orders::getId,model.getId()) |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .set(Orders::getAcceptType,Constants.ONE) |
| | | .set(Orders::getAcceptTime,new Date()) |
| | | .set(Orders::getAcceptMemberId,member.getId()) |
| | | .set(Orders::getStatus,Constants.ordersStatus.accept.getKey()) |
| | | ); |
| | | } |
| | | |
| | | //更新接单量 |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda().setSql(" RECEIVE_NUM = (ifnull(RECEIVE_NUM,0) + 1 )").eq(Member::getId,member.getId())); |
| | | IPage<MyOrderVO> vPage = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); |
| | | PageData<MyOrderVO> pageData = PageData.from(vPage); |
| | | pageData.setRecords(voList); |
| | | pageData.setTotal(orderPage.getTotal()); |
| | | pageData.setPage(orderPage.getCurrent()); |
| | | pageData.setCapacity(orderPage.getSize()); |
| | | return pageData; |
| | | } |
| | | |
| | | //创建操作日志 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.AUTO; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),member.getId(),null); |
| | | @Override |
| | | public PageData<MyOrderVO> findShopOrderPage(PageWrap<MyOrderDTO> pageWrap, Integer shopId) { |
| | | MyOrderDTO model = pageWrap.getModel(); |
| | | Integer status = model != null ? model.getStatus() : null; |
| | | Integer combinedStatus = model != null ? model.getCombinedStatus() : null; |
| | | |
| | | IdentityInfo wokerIdentityInfo = identityInfoMapper.selectOne(new QueryWrapper<IdentityInfo>().lambda() |
| | | .eq(IdentityInfo::getMemberId,member.getId()) |
| | | .eq(IdentityInfo::getType,orders.getType()) |
| | | .eq(IdentityInfo::getAuditStatus,Constants.TWO) |
| | | .last("limit 1") |
| | | ); |
| | | //通知发单方 |
| | | if(org.apache.commons.lang3.StringUtils.isNotBlank(releaseMember.getOpenid())&&Objects.nonNull(wokerIdentityInfo)){ |
| | | //发送微信通知 |
| | | sendWxMessage.acceptMessage(releaseMember.getOpenid(),orders,wokerIdentityInfo.getLinkName(),wokerIdentityInfo.getTelephone()); |
| | | // 解析合并状态为具体状态列表 |
| | | List<Integer> statusList = null; |
| | | if (combinedStatus != null) { |
| | | Constants.OrderCombinedStatus combined = Constants.OrderCombinedStatus.getByKey(combinedStatus); |
| | | if (combined != null) { |
| | | statusList = new ArrayList<>(); |
| | | for (int s : combined.getStatuses()) { |
| | | statusList.add(s); |
| | | } |
| | | } |
| | | } |
| | | |
| | | //通知接单方 |
| | | sendWxMessage.autoDispatchMessage(member.getOpenid(),orders,GeoUtils.haversineDistance( |
| | | orders.getLgt().doubleValue(), orders.getLat().doubleValue(), |
| | | wokerIdentityInfo.getLgt().doubleValue(), |
| | | wokerIdentityInfo.getLat().doubleValue() |
| | | )); |
| | | |
| | | aliSmsService.businessSendSms(Constants.smsContent.dispatch.getKey(),orders.getLinkPhone(),orders,null, |
| | | null,categoryMapper); |
| | | IPage<Orders> p = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); |
| | | MPJLambdaWrapper<Orders> wrapper = new MPJLambdaWrapper<Orders>() |
| | | .selectAll(Orders.class) |
| | | .select("s1.name", Orders::getDepositShopName) |
| | | .select("s1.link_name", Orders::getDepositShopLinkName) |
| | | .select("s1.link_phone", Orders::getDepositShopLinkPhone) |
| | | .select("s2.name", Orders::getTakeShopName) |
| | | .select("s2.address", Orders::getTakeShopAddress) |
| | | .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); |
| | | |
| | | IPage<Orders> orderPage = ordersMapper.selectJoinPage(p, Orders.class, wrapper); |
| | | List<MyOrderVO> voList = new ArrayList<>(); |
| | | if (orderPage != null && orderPage.getRecords() != null) { |
| | | for (Orders o : orderPage.getRecords()) { |
| | | MyOrderVO vo = new MyOrderVO(); |
| | | vo.setId(o.getId()); |
| | | vo.setCode(o.getCode()); |
| | | vo.setType(o.getType()); |
| | | vo.setStatus(o.getStatus()); |
| | | vo.setCreateTime(o.getCreateTime()); |
| | | vo.setExpectedTakeTime(o.getExpectedTakeTime()); |
| | | |
| | | vo.setDepositShopName(o.getDepositShopName()); |
| | | vo.setDepositShopLinkName(o.getDepositShopLinkName()); |
| | | vo.setDepositShopPhone(o.getDepositShopLinkPhone()); |
| | | |
| | | // 门店角色:存件门店=1,取件门店=2 |
| | | if (Constants.equalsInteger(o.getDepositShopId(), shopId)) { |
| | | vo.setShopRole(Constants.ONE); |
| | | } else if (Constants.equalsInteger(o.getTakeShopId(), shopId)) { |
| | | vo.setShopRole(Constants.TWO); |
| | | } |
| | | |
| | | if (o.getTakeShopId() != null) { |
| | | vo.setTakeShopName(o.getTakeShopName()); |
| | | vo.setTakeShopAddress(o.getTakeShopAddress()); |
| | | } else { |
| | | vo.setTakeLocation(o.getTakeLocation()); |
| | | vo.setTakeLocationRemark(o.getTakeLocationRemark()); |
| | | } |
| | | |
| | | vo.setTakeUser(o.getTakeUser()); |
| | | vo.setTakePhone(o.getTakePhone()); |
| | | vo.setDeclaredFee(o.getDeclaredFee()); |
| | | vo.setEstimatedAmount(o.getEstimatedAmount()); |
| | | |
| | | List<OrdersDetail> details = ordersDetailMapper.selectList( |
| | | new QueryWrapper<OrdersDetail>().lambda() |
| | | .eq(OrdersDetail::getOrderId, o.getId()) |
| | | .eq(OrdersDetail::getDeleted, Constants.ZERO)); |
| | | |
| | | 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()); |
| | | } |
| | | voList.add(vo); |
| | | } |
| | | } |
| | | |
| | | IPage<MyOrderVO> vPage = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); |
| | | PageData<MyOrderVO> pageData = PageData.from(vPage); |
| | | pageData.setRecords(voList); |
| | | pageData.setTotal(orderPage.getTotal()); |
| | | pageData.setPage(orderPage.getCurrent()); |
| | | pageData.setCapacity(orderPage.getSize()); |
| | | return pageData; |
| | | } |
| | | |
| | | @Override |
| | | public MyOrderDetailVO findMyOrderDetail(Integer id, Integer memberId) { |
| | | Orders order = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getId, id) |
| | | .eq(Orders::getMemberId, memberId) |
| | | .eq(Orders::getDeleted, Constants.ZERO)); |
| | | if (order == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | return buildOrderDetailVO(order, true); |
| | | } |
| | | |
| | | @Override |
| | | public MyOrderDetailVO findShopOrderDetail(Integer orderId, String verifyCode) { |
| | | Orders order = null; |
| | | if (orderId != null) { |
| | | order = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getId, orderId) |
| | | .eq(Orders::getDeleted, Constants.ZERO)); |
| | | } else if (StringUtils.isNotBlank(verifyCode)) { |
| | | order = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getMemberVerifyCode, verifyCode) |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (order == null) { |
| | | order = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getDriverVerifyCode, verifyCode) |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | } |
| | | } |
| | | if (order == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在"); |
| | | } |
| | | return buildOrderDetailVO(order, false); |
| | | } |
| | | |
| | | /** |
| | | * 构建订单详情VO(会员端/门店端复用) |
| | | * |
| | | * @param order 订单实体 |
| | | * @param memberViewMode true=会员端(按条件返回核销码),false=门店端(始终返回核销码) |
| | | */ |
| | | private MyOrderDetailVO buildOrderDetailVO(Orders order, boolean memberViewMode) { |
| | | MyOrderDetailVO vo = new MyOrderDetailVO(); |
| | | vo.setId(order.getId()); |
| | | vo.setStatus(order.getStatus()); |
| | | vo.setType(order.getType()); |
| | | vo.setCode(order.getCode()); |
| | | vo.setOutTradeNo(order.getOutTradeNo()); |
| | | vo.setRemark(order.getRemark()); |
| | | vo.setCreateTime(order.getCreateTime()); |
| | | vo.setPayTime(order.getPayTime()); |
| | | vo.setExpectedDepositTime(order.getExpectedDepositTime()); |
| | | vo.setExpectedTakeTime(order.getExpectedTakeTime()); |
| | | vo.setArriveTime(order.getArriveTime()); |
| | | |
| | | // 费用(分) |
| | | vo.setBasicAmount(order.getBasicAmount()); |
| | | vo.setDeclaredAmount(order.getDeclaredAmount()); |
| | | vo.setDeclaredFee(order.getDeclaredFee()); |
| | | vo.setUrgentAmount(order.getUrgentAmount()); |
| | | vo.setActualPayAmount(order.getPayAmount()); |
| | | |
| | | // 标记 |
| | | vo.setExceptionStatus(order.getExceptionStatus()); |
| | | |
| | | // 是否超出取件时间 |
| | | vo.setPastTakeTime(order.getExpectedTakeTime() != null && new Date().after(order.getExpectedTakeTime())); |
| | | |
| | | // 订单状态描述 + 倒计时 |
| | | vo.setStatusDesc(buildStatusDesc(order)); |
| | | if (Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.waitPay.getStatus())) { |
| | | vo.setPayCountdownMs(calcPayCountdownMs(order)); |
| | | } |
| | | |
| | | // 存件门店 |
| | | if (order.getDepositShopId() != null) { |
| | | ShopInfo depositShop = shopInfoMapper.selectById(order.getDepositShopId()); |
| | | if (depositShop != null) { |
| | | vo.setDepositShopName(depositShop.getName()); |
| | | vo.setDepositShopLinkName(depositShop.getLinkName()); |
| | | vo.setDepositShopPhone(depositShop.getLinkPhone()); |
| | | vo.setDepositShopAddress(depositShop.getAddress()); |
| | | } |
| | | } |
| | | |
| | | // 取件信息 |
| | | if (order.getTakeShopId() != null) { |
| | | ShopInfo takeShop = shopInfoMapper.selectById(order.getTakeShopId()); |
| | | if (takeShop != null) { |
| | | vo.setTakeShopName(takeShop.getName()); |
| | | vo.setTakeShopAddress(takeShop.getAddress()); |
| | | } |
| | | } else { |
| | | vo.setTakeLocation(order.getTakeLocation()); |
| | | vo.setTakeLocationRemark(order.getTakeLocationRemark()); |
| | | } |
| | | |
| | | // 取件联系人 |
| | | vo.setTakeUser(order.getTakeUser()); |
| | | vo.setTakePhone(order.getTakePhone()); |
| | | |
| | | // 物品类型名称 |
| | | if (order.getGoodType() != null) { |
| | | Category category = categoryMapper.selectById(order.getGoodType()); |
| | | if (category != null) { |
| | | vo.setGoodTypeName(category.getName()); |
| | | } |
| | | } |
| | | |
| | | // 下单照片 |
| | | String imgPrefix = getOrdersPrefix(); |
| | | vo.setOrderImages(getFileUrls(order.getId(), Constants.FileType.ORDER_FILE.getKey(), imgPrefix)); |
| | | |
| | | // 物品明细 |
| | | List<OrdersDetail> details = ordersDetailMapper.selectList( |
| | | new QueryWrapper<OrdersDetail>().lambda() |
| | | .eq(OrdersDetail::getOrderId, order.getId()) |
| | | .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()); |
| | | |
| | | // 核销码 |
| | | Integer status = order.getStatus(); |
| | | if (memberViewMode) { |
| | | // 会员端:待寄存(1)返回;待取件(5)时,就地寄存无取件门店不返回 |
| | | boolean returnCode = false; |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.waitDeposit.getStatus())) { |
| | | returnCode = true; |
| | | } else if (Constants.equalsInteger(status, Constants.OrderStatus.arrived.getStatus())) { |
| | | if (!(Constants.equalsInteger(order.getType(), Constants.ZERO) && order.getTakeShopId() == null)) { |
| | | returnCode = true; |
| | | } |
| | | } |
| | | if (returnCode) { |
| | | vo.setMemberVerifyCode(order.getMemberVerifyCode()); |
| | | } |
| | | } else { |
| | | // 门店端:始终返回会员核销码 |
| | | vo.setMemberVerifyCode(order.getMemberVerifyCode()); |
| | | } |
| | | |
| | | return vo; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void cancelOrder(Integer orderId, Integer memberId, String reason) { |
| | | Orders order = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getId, orderId) |
| | | .eq(Orders::getMemberId, memberId) |
| | | .eq(Orders::getDeleted, Constants.ZERO)); |
| | | if (order == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | |
| | | // 仅异地寄存可取消 |
| | | if (!Constants.equalsInteger(order.getType(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅异地寄存订单可取消"); |
| | | } |
| | | |
| | | Integer status = order.getStatus(); |
| | | if (status == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单状态异常"); |
| | | } |
| | | |
| | | Date now = new Date(); |
| | | |
| | | // 待支付:直接取消 |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.waitPay.getStatus())) { |
| | | order.setStatus(Constants.OrderStatus.cancelled.getStatus()); |
| | | order.setCancelTime(now); |
| | | ordersMapper.updateById(order); |
| | | saveCancelLog(order, "会员取消订单(待支付)", reason, memberId); |
| | | return; |
| | | } |
| | | |
| | | // 待寄存:直接取消,全额退款 |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.waitDeposit.getStatus())) { |
| | | // 记录退款信息 |
| | | OrdersRefund refund = new OrdersRefund(); |
| | | refund.setOrderId(orderId); |
| | | refund.setType(0); // 未寄存直接取消 |
| | | refund.setCancelInfo(reason); |
| | | refund.setCreateTime(now); |
| | | refund.setDeleted(Constants.ZERO); |
| | | |
| | | // 调用微信退款,全额退款 |
| | | String refundCode = wxMiniUtilService.wxRefund(order.getOutTradeNo(), order.getPayAmount(), order.getPayAmount()); |
| | | refund.setRefundCode(refundCode); |
| | | refund.setRefundTime(new Date()); |
| | | ordersRefundMapper.insert(refund); |
| | | |
| | | order.setStatus(Constants.OrderStatus.cancelled.getStatus()); |
| | | order.setCancelTime(now); |
| | | order.setRefundAmount(order.getPayAmount()); |
| | | ordersMapper.updateById(order); |
| | | |
| | | saveCancelLog(order, "会员取消订单(待寄存,全额退款)", reason, memberId); |
| | | return; |
| | | } |
| | | |
| | | // 已寄存/已接单:进入取消中状态 |
| | | 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); |
| | | return; |
| | | } |
| | | |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不允许取消"); |
| | | } |
| | | |
| | | /** |
| | | * 保存取消订单操作日志 |
| | | */ |
| | | private void saveCancelLog(Orders order, String title, 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.setOrderStatus(order.getStatus()); |
| | | log.setOptUserId(memberId); |
| | | log.setOptUserType(0); // 0=用户 |
| | | log.setCreateTime(new Date()); |
| | | log.setDeleted(Constants.ZERO); |
| | | orderLogService.create(log); |
| | | } |
| | | |
| | | /** |
| | | * 保存门店核销日志 |
| | | */ |
| | | private void saveShopVerifyLog(Orders order, String title, String logInfo, String remark, Integer shopId) { |
| | | OrderLog log = new OrderLog(); |
| | | log.setOrderId(order.getId()); |
| | | log.setTitle(title); |
| | | log.setLogInfo(logInfo); |
| | | log.setRemark(remark); |
| | | log.setOrderStatus(order.getStatus()); |
| | | log.setOptUserId(shopId); |
| | | log.setOptUserType(2); // 2=门店 |
| | | log.setCreateTime(new Date()); |
| | | log.setDeleted(Constants.ZERO); |
| | | orderLogService.create(log); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void handleStorageOrderPayNotify(String outTradeNo, String wxTradeNo) { |
| | | Orders order = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getOutTradeNo, outTradeNo) |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (order == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在: " + outTradeNo); |
| | | } |
| | | // 幂等:已支付则跳过 |
| | | if (Constants.equalsInteger(order.getPayStatus(), Constants.ONE)) { |
| | | return; |
| | | } |
| | | Date now = new Date(); |
| | | order.setStatus(Constants.OrderStatus.waitDeposit.getStatus()); // 待寄存 |
| | | order.setPayStatus(Constants.ONE); // 已支付 |
| | | order.setPayTime(now); |
| | | order.setWxExternalNo(wxTradeNo); |
| | | order.setUpdateTime(now); |
| | | // 生成会员核销码 |
| | | order.setMemberVerifyCode(generateVerifyCode()); |
| | | ordersMapper.updateById(order); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public PayResponse payOverdueFee(Integer orderId, Integer memberId) { |
| | | // 1. 查询寄存订单 |
| | | Orders order = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getId, orderId) |
| | | .eq(Orders::getMemberId, memberId) |
| | | .eq(Orders::getDeleted, Constants.ZERO)); |
| | | if (order == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在"); |
| | | } |
| | | // 2. 校验状态:待取件(5) + 逾期(1) |
| | | if (!Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.arrived.getStatus())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不支持逾期支付"); |
| | | } |
| | | if (!Constants.equalsInteger(order.getOverdueStatus(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单不存在逾期费用"); |
| | | } |
| | | if (order.getOverdueAmount() == null || order.getOverdueAmount() <= 0) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "逾期费用异常,无法发起支付"); |
| | | } |
| | | // 3. 查询会员 |
| | | Member member = memberMapper.selectById(memberId); |
| | | if (member == null || StringUtils.isBlank(member.getOpenid())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "用户信息异常,无法发起支付"); |
| | | } |
| | | // 4. 创建逾期费用订单 |
| | | String outTradeNo = generateOrderTradeNo(); |
| | | Date now = new Date(); |
| | | OtherOrders otherOrders = new OtherOrders(); |
| | | otherOrders.setType(Constants.TWO); // 2=逾期费用订单 |
| | | otherOrders.setMemberId(memberId); |
| | | otherOrders.setOrderId(orderId); |
| | | otherOrders.setPayAccount(order.getOverdueAmount()); |
| | | otherOrders.setPayStatus(Constants.ZERO); |
| | | otherOrders.setCode("OD" + new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(now) + orderId); |
| | | otherOrders.setOutTradeNo(outTradeNo); |
| | | otherOrders.setDeleted(Constants.ZERO); |
| | | otherOrders.setCreateTime(now); |
| | | otherOrdersMapper.insert(otherOrders); |
| | | |
| | | // 5. 唤起微信支付 |
| | | return wxPayForOtherOrder(otherOrders, member.getOpenid(), Constants.OrdersAttach.OVERDUE_FEE); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void handleOverdueFeePayNotify(String outTradeNo, String wxTradeNo) { |
| | | // 1. 查找逾期费用订单 |
| | | OtherOrders otherOrders = otherOrdersMapper.selectOne(new QueryWrapper<OtherOrders>().lambda() |
| | | .eq(OtherOrders::getOutTradeNo, outTradeNo) |
| | | .eq(OtherOrders::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (otherOrders == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "逾期费用订单不存在: " + outTradeNo); |
| | | } |
| | | // 2. 幂等:已支付则跳过 |
| | | if (Constants.equalsInteger(otherOrders.getPayStatus(), Constants.ONE)) { |
| | | return; |
| | | } |
| | | Date now = new Date(); |
| | | // 3. 更新逾期费用订单状态 |
| | | otherOrders.setPayStatus(Constants.ONE); |
| | | otherOrders.setPayTime(now); |
| | | otherOrders.setWxExternalNo(wxTradeNo); |
| | | otherOrders.setUpdateTime(now); |
| | | otherOrdersMapper.updateById(otherOrders); |
| | | |
| | | // 4. 更新寄存订单逾期状态为已支付(2),更新总金额,重算三方收益 |
| | | if (otherOrders.getOrderId() != null) { |
| | | Orders order = ordersMapper.selectById(otherOrders.getOrderId()); |
| | | if (order != null) { |
| | | order.setOverdueStatus(Constants.TWO); // 2=已支付 |
| | | // 总金额 = 原金额 + 逾期费用 |
| | | Long overdueFee = otherOrders.getPayAccount() != null ? otherOrders.getPayAccount() : 0L; |
| | | long newTotal = (order.getTotalAmount() != null ? order.getTotalAmount() : 0L) + overdueFee; |
| | | order.setTotalAmount(newTotal); |
| | | order.setUpdateTime(now); |
| | | ordersMapper.updateById(order); |
| | | // 重算三方收益 |
| | | calculateAndSaveOrderFees(order.getId()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | //自动评价 订单完成7天后自动评价4星 |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class,BusinessException.class}) |
| | | public void autoComment(){ |
| | | List<Orders> ordersList = ordersMapper.selectList(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getStatus,Constants.FOUR).eq(Orders::getCommentStatus,Constants.ZERO) |
| | | .apply(" DATE_ADD(finish_time, INTERVAL 7 DAY) < now() ") |
| | | .last("limit 100") |
| | | ); |
| | | public void deleteMyOrder(Integer orderId, Integer memberId) { |
| | | Orders order = ordersMapper.selectById(orderId); |
| | | if (order == null || !Constants.equalsInteger(order.getDeleted(), Constants.ZERO)) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | if (!Constants.equalsInteger(order.getMemberId(), memberId)) { |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "无权操作此订单"); |
| | | } |
| | | // 仅已完成(7)、已取消(99)、已退款(96)可删除 |
| | | int status = Constants.formatIntegerNum(order.getStatus()); |
| | | if (status != Constants.OrderStatus.finished.getStatus() |
| | | && status != Constants.OrderStatus.cancelled.getStatus() |
| | | && status != Constants.OrderStatus.closed.getStatus()) { |
| | | throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "当前订单状态不可删除"); |
| | | } |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getDeleted, Constants.ONE) |
| | | .set(Orders::getUpdateTime, new Date()) |
| | | .eq(Orders::getId, orderId)); |
| | | } |
| | | |
| | | for (Orders orders:ordersList) { |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public PayResponse payShopDeposit(Integer shopId) { |
| | | // 1. 查询门店信息 |
| | | ShopInfo shopInfo = shopInfoMapper.selectById(shopId); |
| | | if (shopInfo == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "门店不存在"); |
| | | } |
| | | // 2. 校验状态:审批通过(1)才能支付押金 |
| | | if (!Constants.equalsInteger(shopInfo.getAuditStatus(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前门店状态不支持支付押金"); |
| | | } |
| | | if (shopInfo.getDepositAmount() == null || shopInfo.getDepositAmount() <= 0) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "押金金额异常,无法发起支付"); |
| | | } |
| | | // 3. 查询会员openid |
| | | Member member = memberMapper.selectById(shopInfo.getRegionMemberId()); |
| | | if (member == null || StringUtils.isBlank(member.getOpenid())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "用户信息异常,无法发起支付"); |
| | | } |
| | | // 4. 创建押金订单 |
| | | String outTradeNo = generateOrderTradeNo(); |
| | | Date now = new Date(); |
| | | OtherOrders otherOrders = new OtherOrders(); |
| | | otherOrders.setType(Constants.ZERO); // 0=店铺押金订单 |
| | | otherOrders.setMemberId(shopInfo.getRegionMemberId()); |
| | | otherOrders.setPayAccount(shopInfo.getDepositAmount()); |
| | | otherOrders.setPayStatus(Constants.ZERO); |
| | | otherOrders.setCode("SD" + new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(now) + shopId); |
| | | otherOrders.setOutTradeNo(outTradeNo); |
| | | otherOrders.setDeleted(Constants.ZERO); |
| | | otherOrders.setCreateTime(now); |
| | | otherOrdersMapper.insert(otherOrders); |
| | | |
| | | // 5. 唤起微信支付 |
| | | return wxPayForOtherOrder(otherOrders, member.getOpenid(), Constants.OrdersAttach.SHOP_DEPOSIT); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void handleShopDepositPayNotify(String outTradeNo, String wxTradeNo) { |
| | | // 1. 查找押金订单 |
| | | OtherOrders otherOrders = otherOrdersMapper.selectOne(new QueryWrapper<OtherOrders>().lambda() |
| | | .eq(OtherOrders::getOutTradeNo, outTradeNo) |
| | | .eq(OtherOrders::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (otherOrders == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "押金订单不存在: " + outTradeNo); |
| | | } |
| | | // 2. 幂等:已支付则跳过 |
| | | if (Constants.equalsInteger(otherOrders.getPayStatus(), Constants.ONE)) { |
| | | return; |
| | | } |
| | | Date now = new Date(); |
| | | // 3. 更新押金订单状态 |
| | | otherOrders.setPayStatus(Constants.ONE); |
| | | otherOrders.setPayTime(now); |
| | | otherOrders.setWxExternalNo(wxTradeNo); |
| | | otherOrders.setUpdateTime(now); |
| | | otherOrdersMapper.updateById(otherOrders); |
| | | |
| | | // 4. 查询门店信息(通过注册会员主键关联) |
| | | ShopInfo shopInfo = shopInfoMapper.selectOne(new QueryWrapper<ShopInfo>().lambda() |
| | | .eq(ShopInfo::getRegionMemberId, otherOrders.getMemberId()) |
| | | .eq(ShopInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (shopInfo == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "门店不存在"); |
| | | } |
| | | // 5. 更新门店状态:已支付押金 |
| | | shopInfo.setAuditStatus(Constants.THREE); // 3=已支付押金 |
| | | shopInfo.setPayStatus(Constants.ONE); |
| | | shopInfo.setPayTime(now); |
| | | shopInfo.setWxExternalNo(wxTradeNo); |
| | | shopInfo.setCode(otherOrders.getCode()); |
| | | Member member = memberMapper.selectById(otherOrders.getMemberId()); |
| | | if (member != null) { |
| | | shopInfo.setPayMemberOpenId(member.getOpenid()); |
| | | } |
| | | shopInfo.setUpdateTime(now); |
| | | shopInfoMapper.updateById(shopInfo); |
| | | |
| | | // 6. 押金支付完成后,若城市未开通则自动开通 |
| | | if (shopInfo.getAreaId() != null) { |
| | | Areas shopArea = areasBiz.resolveArea(shopInfo.getAreaId()); |
| | | if (shopArea != null && shopArea.getParentId() != null) { |
| | | Areas cityArea = areasBiz.resolveArea(shopArea.getParentId()); |
| | | if (cityArea != null && !Constants.equalsInteger(cityArea.getStatus(), Constants.ONE)) { |
| | | cityArea.setStatus(Constants.ONE); |
| | | cityArea.setEditDate(now); |
| | | areasService.updateById(cityArea); |
| | | areasService.cacheData(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void settleOrders() { |
| | | // 1. 读取结算天数配置 |
| | | SystemDictData settlementConfig = systemDictDataBiz.queryByCode(Constants.OPERATION_CONFIG, Constants.OP_SETTLEMENT_DATE); |
| | | if (settlementConfig == null || StringUtils.isBlank(settlementConfig.getCode())) { |
| | | return; |
| | | } |
| | | int days = Integer.parseInt(settlementConfig.getCode()); |
| | | // 结算截止时间 = 当前时间 - N天 |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.add(Calendar.DAY_OF_MONTH, -days); |
| | | Date deadline = cal.getTime(); |
| | | |
| | | // 2. 查询已完成的待结算订单(完成时间 <= 截止时间) |
| | | List<Orders> ordersList = ordersMapper.selectList(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .eq(Orders::getStatus, Constants.OrderStatus.finished.getStatus()) |
| | | .eq(Orders::getSettlementStatus, Constants.ZERO) |
| | | .le(Orders::getFinishTime, deadline)); |
| | | if (ordersList == null || ordersList.isEmpty()) { |
| | | return; |
| | | } |
| | | |
| | | Date now = new Date(); |
| | | for (Orders order : ordersList) { |
| | | // 3. 更新订单结算状态 |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getCommentStatus,Constants.ONE) |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .set(Orders::getCommentTime,new Date()) |
| | | .set(Orders::getCommentLevel,Constants.FOUR) |
| | | .set(Orders::getCommentType,Constants.ZERO) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | .set(Orders::getSettlementStatus, Constants.ONE) |
| | | .set(Orders::getSettlementTime, now) |
| | | .set(Orders::getUpdateTime, now) |
| | | .eq(Orders::getId, order.getId())); |
| | | |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda() |
| | | .setSql(" score = ( ( total_score +" + Constants.FOUR + " ) / (score_order_num + 1 ) ) ") |
| | | .setSql(" total_score = ( total_score +" + Constants.FOUR + ")") |
| | | .setSql(" score_order_num = ( score_order_num + 1 ) " ).eq(Member::getId,orders.getAcceptMemberId()) |
| | | ); |
| | | // 4. 查询关联的待入账 Revenue 记录 |
| | | List<Revenue> revenues = revenueMapper.selectList(new QueryWrapper<Revenue>().lambda() |
| | | .eq(Revenue::getObjId, order.getId()) |
| | | .eq(Revenue::getObjType, Constants.ZERO) |
| | | .eq(Revenue::getVaildStatus, Constants.ZERO) |
| | | .eq(Revenue::getDeleted, Constants.ZERO)); |
| | | |
| | | //日志存储 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.AUTO_COMMENT; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),orders.getAcceptMemberId(),null); |
| | | } |
| | | } |
| | | for (Revenue revenue : revenues) { |
| | | Long amount = revenue.getAmount() != null ? revenue.getAmount() : 0L; |
| | | // 更新 Revenue 为已入账 |
| | | revenueMapper.update(new UpdateWrapper<Revenue>().lambda() |
| | | .set(Revenue::getVaildStatus, Constants.ONE) |
| | | .set(Revenue::getUpdateTime, now) |
| | | .eq(Revenue::getId, revenue.getId())); |
| | | |
| | | |
| | | //自动确认 订单修改后若未处理 根据配置自动处理 |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class,BusinessException.class}) |
| | | public void autoConfirm(){ |
| | | String autoConfirmTime = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.AUTO_CONFIRM).getCode(); |
| | | List<Orders> ordersList = ordersMapper.selectList(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getStatus,Constants.ordersStatus.accept.getKey()) |
| | | .eq(Orders::getIsUpdate,Constants.ONE) |
| | | .apply(" DATE_ADD(IS_UPDATE_TIME, INTERVAL "+autoConfirmTime+" MINUTE) < now() ") |
| | | .last("limit 100") |
| | | ); |
| | | if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(ordersList)){ |
| | | for (Orders orders:ordersList) { |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getIsUpdate,Constants.TWO) |
| | | .set(Orders::getUpdateTime,new Date()) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | //记录同意修改的日志 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.AUTO_AGREE; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),null,null); |
| | | // 根据 memberType 更新余额 |
| | | if (Constants.equalsInteger(revenue.getMemberType(), Constants.ONE)) { |
| | | // 司机:通过 memberId 查 DriverInfo,更新 balance / totalBalance |
| | | DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda() |
| | | .eq(DriverInfo::getMemberId, revenue.getMemberId()) |
| | | .eq(DriverInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (driver != null) { |
| | | driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda() |
| | | .setSql(" BALANCE = IFNULL(BALANCE, 0) + " + amount) |
| | | .setSql(" TOTAL_BALANCE = IFNULL(TOTAL_BALANCE, 0) + " + amount) |
| | | .eq(DriverInfo::getId, driver.getId())); |
| | | } |
| | | } else if (Constants.equalsInteger(revenue.getMemberType(), Constants.TWO)) { |
| | | // 门店:通过 memberId 查 ShopInfo(regionMemberId),更新 balance / totalBalance |
| | | ShopInfo shop = shopInfoMapper.selectOne(new QueryWrapper<ShopInfo>().lambda() |
| | | .eq(ShopInfo::getRegionMemberId, revenue.getMemberId()) |
| | | .eq(ShopInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (shop != null) { |
| | | shopInfoMapper.update(new UpdateWrapper<ShopInfo>().lambda() |
| | | .setSql(" BALANCE = IFNULL(BALANCE, 0) + " + amount) |
| | | .setSql(" TOTAL_BALANCE = IFNULL(TOTAL_BALANCE, 0) + " + amount) |
| | | .eq(ShopInfo::getId, shop.getId())); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | //自动取消 订单未支付 |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class,BusinessException.class}) |
| | | public void autoCancelWaitPay(){ |
| | | List<Orders> ordersList = ordersMapper.selectList(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getStatus,Constants.ordersStatus.waitPay) |
| | | .apply(" DATE_ADD(CREATE_TIME, INTERVAL 15 MINUTE) < now() ") |
| | | .last("limit 100") |
| | | ); |
| | | if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(ordersList)){ |
| | | for (Orders orders:ordersList) { |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getStatus,Constants.ordersStatus.cancel.getKey()) |
| | | .set(Orders::getUpdateTime,DateUtil.getCurrDateTime()) |
| | | .set(Orders::getCancelTime,DateUtil.getCurrDateTime()) |
| | | .set(Orders::getCancelType,Constants.TWO) |
| | | .eq(Orders::getId,orders.getId()) |
| | | ); |
| | | //记录同意修改的日志 |
| | | Constants.OrdersLog ordersLog = Constants.OrdersLog.SYSTEM_CANCEL; |
| | | this.saveOrderLog(orders,ordersLog, |
| | | ordersLog.getInfo(),orders.getAcceptMemberId(),null); |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void commentOrder(CommentOrderDTO dto, Integer memberId) { |
| | | // 1. 校验订单 |
| | | Orders order = ordersMapper.selectById(dto.getOrderId()); |
| | | if (order == null || Constants.equalsInteger(order.getDeleted(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在"); |
| | | } |
| | | if (!Constants.equalsInteger(order.getMemberId(), memberId)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "无权评价该订单"); |
| | | } |
| | | if (!Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.finished.getStatus())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不支持评价"); |
| | | } |
| | | if (Constants.equalsInteger(order.getCommentStatus(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单已评价"); |
| | | } |
| | | |
| | | // 2. 异地寄存订单:取件门店和司机评分校验 |
| | | boolean isRemote = Constants.equalsInteger(order.getType(), Constants.ONE); |
| | | if (isRemote) { |
| | | if (dto.getDriverScore() == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "异地寄存订单必须评价司机"); |
| | | } |
| | | if (order.getTakeShopId() != null && dto.getTakeScore() == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请评价取件门店"); |
| | | } |
| | | } |
| | | |
| | | Date now = new Date(); |
| | | |
| | | // 3. 更新订单评价状态 |
| | | order.setCommentStatus(Constants.ONE); |
| | | order.setCommentInfo(dto.getContent()); |
| | | order.setCommentDepositLevel(dto.getDepositScore()); |
| | | order.setCommentTakeLevel(dto.getTakeScore()); |
| | | order.setCommentDriverLevel(dto.getDriverScore()); |
| | | order.setCommentTime(now); |
| | | order.setUpdateTime(now); |
| | | ordersMapper.updateById(order); |
| | | |
| | | // 4. 创建评价记录 |
| | | // 4.1 存件门店 |
| | | OrderComment depositComment = new OrderComment(); |
| | | depositComment.setOrderId(order.getId()); |
| | | depositComment.setOrderCode(order.getCode()); |
| | | depositComment.setMemberId(memberId); |
| | | depositComment.setTargetType(Constants.ONE); // 1=存件门店 |
| | | depositComment.setTargetId(order.getDepositShopId()); |
| | | depositComment.setScore(dto.getDepositScore()); |
| | | depositComment.setContent(dto.getContent()); |
| | | depositComment.setDeleted(Constants.ZERO); |
| | | depositComment.setCreateTime(now); |
| | | orderCommentMapper.insert(depositComment); |
| | | |
| | | // 4.2 取件门店(异地寄存且有取件门店) |
| | | if (isRemote && order.getTakeShopId() != null && dto.getTakeScore() != null) { |
| | | OrderComment takeComment = new OrderComment(); |
| | | takeComment.setOrderId(order.getId()); |
| | | takeComment.setOrderCode(order.getCode()); |
| | | takeComment.setMemberId(memberId); |
| | | takeComment.setTargetType(Constants.TWO); // 2=取件门店 |
| | | takeComment.setTargetId(order.getTakeShopId()); |
| | | takeComment.setScore(dto.getTakeScore()); |
| | | takeComment.setContent(dto.getContent()); |
| | | takeComment.setDeleted(Constants.ZERO); |
| | | takeComment.setCreateTime(now); |
| | | orderCommentMapper.insert(takeComment); |
| | | } |
| | | |
| | | // 4.3 司机(异地寄存) |
| | | if (isRemote && order.getAcceptDriver() != null && dto.getDriverScore() != null) { |
| | | OrderComment driverComment = new OrderComment(); |
| | | driverComment.setOrderId(order.getId()); |
| | | driverComment.setOrderCode(order.getCode()); |
| | | driverComment.setMemberId(memberId); |
| | | driverComment.setTargetType(Constants.THREE); // 3=司机 |
| | | driverComment.setTargetId(order.getAcceptDriver()); |
| | | driverComment.setScore(dto.getDriverScore()); |
| | | driverComment.setContent(dto.getContent()); |
| | | driverComment.setDeleted(Constants.ZERO); |
| | | driverComment.setCreateTime(now); |
| | | orderCommentMapper.insert(driverComment); |
| | | } |
| | | |
| | | // 5. 更新门店/司机平均评分 |
| | | updateTargetScore(Constants.ONE, order.getDepositShopId()); |
| | | if (isRemote && order.getTakeShopId() != null) { |
| | | updateTargetScore(Constants.TWO, order.getTakeShopId()); |
| | | } |
| | | if (isRemote && order.getAcceptDriver() != null) { |
| | | updateTargetScore(Constants.THREE, order.getAcceptDriver()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 更新评价对象(门店/司机)的平均评分 |
| | | */ |
| | | private void updateTargetScore(Integer targetType, Integer targetId) { |
| | | List<OrderComment> comments = orderCommentMapper.selectList(new QueryWrapper<OrderComment>().lambda() |
| | | .eq(OrderComment::getDeleted, Constants.ZERO) |
| | | .eq(OrderComment::getTargetType, targetType) |
| | | .eq(OrderComment::getTargetId, targetId)); |
| | | if (comments.isEmpty()) { |
| | | return; |
| | | } |
| | | double avg = comments.stream() |
| | | .mapToInt(OrderComment::getScore) |
| | | .average() |
| | | .orElse(0.0); |
| | | BigDecimal score = BigDecimal.valueOf(avg).setScale(1, BigDecimal.ROUND_HALF_UP); |
| | | Date now = new Date(); |
| | | if (Constants.equalsInteger(targetType, Constants.ONE) || Constants.equalsInteger(targetType, Constants.TWO)) { |
| | | ShopInfo shopInfo = shopInfoMapper.selectById(targetId); |
| | | if (shopInfo != null) { |
| | | shopInfo.setScore(score); |
| | | shopInfo.setUpdateTime(now); |
| | | shopInfoMapper.updateById(shopInfo); |
| | | } |
| | | } else if (Constants.equalsInteger(targetType, Constants.THREE)) { |
| | | DriverInfo driverInfo = driverInfoMapper.selectById(targetId); |
| | | if (driverInfo != null) { |
| | | driverInfo.setScore(score); |
| | | driverInfo.setUpdateTime(now); |
| | | driverInfoMapper.updateById(driverInfo); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 唤起微信支付(其他订单) |
| | | */ |
| | | private PayResponse wxPayForOtherOrder(OtherOrders otherOrders, String openid, Constants.OrdersAttach ordersAttach) { |
| | | try { |
| | | WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest(); |
| | | request.setBody(ordersAttach.getName()); |
| | | request.setAttach(ordersAttach.getKey()); |
| | | request.setOutTradeNo(otherOrders.getOutTradeNo()); |
| | | long totalFee = otherOrders.getPayAccount() != null ? otherOrders.getPayAccount() : 0L; |
| | | request.setTotalFee((int) totalFee); |
| | | request.setTimeStart(DateUtil.DateToString(new Date(), "yyyyMMddHHmmss")); |
| | | request.setSpbillCreateIp(Constants.getIpAddr()); |
| | | request.setOpenid(openid); |
| | | |
| | | @Override |
| | | public void initializeCode(){ |
| | | //更新缓存 |
| | | redisTemplate.opsForValue().set(Constants.RedisKeys.ORDER_CODE,0); |
| | | Object response = WxMiniConfig.wxPayService.createOrder(request); |
| | | |
| | | PayResponse payResponse = new PayResponse(); |
| | | payResponse.setResponse(response); |
| | | payResponse.setOrderId(otherOrders.getId()); |
| | | return payResponse; |
| | | } catch (WxPayException e) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "支付调起失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | @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(), "核销码不能为空"); |
| | | } |
| | | // 根据核销码查找订单(会员核销码) |
| | | Orders order = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getMemberVerifyCode, verifyCode) |
| | | .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.OrderStatus.deposited.getStatus()); |
| | | order.setDepositTime(now); |
| | | // 释放当前核销码,生成新的核销码供取件时使用 |
| | | releaseVerifyCode(verifyCode); |
| | | order.setMemberVerifyCode(generateVerifyCode()); |
| | | ordersMapper.updateById(order); |
| | | // 保存寄存图片(obj_type=2 订单寄存图片,最多3张) |
| | | saveVerifyImages(order.getId(), images, Constants.FileType.ORDER_DEPOSIT.getKey(), shopId); |
| | | // 记录订单日志 |
| | | saveShopVerifyLog(order, "门店确认寄存", "门店【" + shopName + "】确认寄存", remark, shopId); |
| | | } 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(), "该订单不属于当前门店,无法核销"); |
| | | } |
| | | // 待取件(5) → 已完成(7) |
| | | order.setStatus(Constants.OrderStatus.finished.getStatus()); |
| | | order.setConfirmArriveTime(now); |
| | | ordersMapper.updateById(order); |
| | | // 订单完成,释放核销码 |
| | | releaseVerifyCode(verifyCode); |
| | | // 保存出库图片(obj_type=13 门店出库图片,最多3张) |
| | | saveVerifyImages(order.getId(), images, Constants.FileType.STORE_OUT.getKey(), shopId); |
| | | // 生成收益记录 |
| | | calculateAndSaveOrderFees(order.getId()); |
| | | generateRevenueRecords(order.getId()); |
| | | // 记录订单日志 |
| | | saveShopVerifyLog(order, "门店确认取件", "门店【" + shopName + "】确认取件,订单完成", remark, shopId); |
| | | } else { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不允许核销"); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void confirmStoreOut(Integer orderId, Integer shopId, List<String> images, String remark) { |
| | | // 1. 查询订单 |
| | | Orders order = ordersMapper.selectById(orderId); |
| | | if (order == null || Constants.equalsInteger(order.getDeleted(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在"); |
| | | } |
| | | // 2. 校验状态:待取件(5) |
| | | if (!Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.arrived.getStatus())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不允许出库"); |
| | | } |
| | | // 3. 校验逾期状态:0=未逾期 或 2=已支付 |
| | | if (order.getOverdueStatus() != null && Constants.equalsInteger(order.getOverdueStatus(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单存在逾期未支付费用,请先完成逾期费用支付"); |
| | | } |
| | | // 4. 校验确认到店时间不为空 |
| | | if (order.getConfirmArriveTime() == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单尚未确认到店,无法出库"); |
| | | } |
| | | // 5. 校验门店与订单关系 |
| | | if (Constants.equalsInteger(order.getType(), Constants.ZERO)) { |
| | | // 就地寄存:取件门店即存件门店 |
| | | if (!shopId.equals(order.getDepositShopId())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单不属于当前门店"); |
| | | } |
| | | } else { |
| | | // 异地寄存:校验取件门店 |
| | | if (order.getTakeShopId() == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单无取件门店,无法出库"); |
| | | } |
| | | if (!shopId.equals(order.getTakeShopId())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单不属于当前门店"); |
| | | } |
| | | } |
| | | |
| | | // 6. 查询门店名称 |
| | | String shopName = ""; |
| | | ShopInfo shopInfo = shopInfoMapper.selectById(shopId); |
| | | if (shopInfo != null) { |
| | | shopName = shopInfo.getName() != null ? shopInfo.getName() : ""; |
| | | } |
| | | |
| | | // 7. 更新订单状态为已完成 |
| | | Date now = new Date(); |
| | | order.setStatus(Constants.OrderStatus.finished.getStatus()); |
| | | order.setFinishTime(now); |
| | | order.setUpdateTime(now); |
| | | ordersMapper.updateById(order); |
| | | |
| | | // 8. 释放核销码 |
| | | if (StringUtils.isNotBlank(order.getMemberVerifyCode())) { |
| | | releaseVerifyCode(order.getMemberVerifyCode()); |
| | | } |
| | | |
| | | // 9. 保存出库图片(obj_type=13 门店出库图片,最多3张) |
| | | saveVerifyImages(order.getId(), images, Constants.FileType.STORE_OUT.getKey(), shopId); |
| | | |
| | | // 10. 如果存在退款金额,先保存退款记录再调用微信退款 |
| | | // 退款记录在退款调用前落库,避免退款成功但本地异常导致无记录 |
| | | if (order.getRefundAmount() != null && order.getRefundAmount() > 0 |
| | | && StringUtils.isNotBlank(order.getOutTradeNo()) |
| | | && order.getPayAmount() != null && order.getPayAmount() > 0) { |
| | | OrdersRefund refundRecord = new OrdersRefund(); |
| | | refundRecord.setOrderId(orderId); |
| | | refundRecord.setType(3); // 出库退款 |
| | | refundRecord.setCreateTime(now); |
| | | refundRecord.setRefundRemark(remark); |
| | | refundRecord.setDeleted(Constants.ZERO); |
| | | ordersRefundMapper.insert(refundRecord); |
| | | |
| | | // 调用微信退款(放在最后,确保前置操作全部成功) |
| | | String refundCode = wxMiniUtilService.wxRefund( |
| | | order.getOutTradeNo(), order.getPayAmount(), order.getRefundAmount()); |
| | | |
| | | // 退款成功后回填退款单号和时间 |
| | | refundRecord.setRefundCode(refundCode); |
| | | refundRecord.setRefundTime(new Date()); |
| | | ordersRefundMapper.updateById(refundRecord); |
| | | } |
| | | |
| | | // 11. 生成收益记录 |
| | | calculateAndSaveOrderFees(orderId); |
| | | generateRevenueRecords(orderId); |
| | | |
| | | // 12. 记录订单日志 |
| | | String logInfo = "门店【" + shopName + "】确认出库,订单完成"; |
| | | if (order.getRefundAmount() != null && order.getRefundAmount() > 0) { |
| | | logInfo += ",退款" + Constants.getFormatMoney(order.getRefundAmount()) + "元"; |
| | | } |
| | | saveShopVerifyLog(order, "门店确认出库", logInfo, remark, shopId); |
| | | } |
| | | |
| | | @Override |
| | | public void calculateAndSaveOrderFees(Integer orderId) { |
| | | Orders order = ordersMapper.selectById(orderId); |
| | | if (order == null || Constants.equalsInteger(order.getDeleted(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在"); |
| | | } |
| | | |
| | | Long totalAmount = order.getTotalAmount() != null ? order.getTotalAmount() : 0L; |
| | | // 费率(为空时默认0) |
| | | BigDecimal depositRate = order.getDepositShopFeeRata() != null ? order.getDepositShopFeeRata() : BigDecimal.ZERO; |
| | | BigDecimal takeRate = order.getTakeShopFeeRata() != null ? order.getTakeShopFeeRata() : BigDecimal.ZERO; |
| | | BigDecimal driverRate = order.getDriverFeeRata() != null ? order.getDriverFeeRata() : BigDecimal.ZERO; |
| | | Long exceptionFeeVal = order.getExceptionFee() != null ? order.getExceptionFee() : 0L; |
| | | |
| | | //存件门店收益 |
| | | Long depositShopFee = new BigDecimal(totalAmount) |
| | | .multiply(depositRate) |
| | | .setScale(0, RoundingMode.HALF_UP) |
| | | .longValue(); |
| | | |
| | | Long takeShopFee = 0L; |
| | | Long driverFee = 0L; |
| | | |
| | | if (Constants.equalsInteger(order.getType(), Constants.TWO)) { |
| | | // 异地寄存:存件门店 + 司机 |
| | | driverFee = new BigDecimal(totalAmount) |
| | | .multiply(driverRate) |
| | | .setScale(0, RoundingMode.HALF_UP) |
| | | .longValue() |
| | | + exceptionFeeVal; |
| | | |
| | | // 异地寄存且有取件门店:加上取件门店收益 |
| | | if (order.getTakeShopId() != null) { |
| | | takeShopFee = new BigDecimal(totalAmount) |
| | | .multiply(takeRate) |
| | | .setScale(0, RoundingMode.HALF_UP) |
| | | .longValue(); |
| | | } |
| | | } |
| | | |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .eq(Orders::getId, orderId) |
| | | .set(Orders::getDepositShopFee, depositShopFee) |
| | | .set(Orders::getTakeShopFee, takeShopFee) |
| | | .set(Orders::getDriverFee, driverFee) |
| | | .set(Orders::getUpdateTime, new Date())); |
| | | } |
| | | |
| | | /** |
| | | * 生成门店/司机收益记录(未结算) |
| | | * 订单完成时调用,读取订单上已计算好的费用字段 |
| | | */ |
| | | private void generateRevenueRecords(Integer orderId) { |
| | | Orders order = ordersMapper.selectById(orderId); |
| | | if (order == null) { |
| | | return; |
| | | } |
| | | Date now = new Date(); |
| | | Long depositShopFee = order.getDepositShopFee() != null ? order.getDepositShopFee() : 0L; |
| | | Long takeShopFee = order.getTakeShopFee() != null ? order.getTakeShopFee() : 0L; |
| | | Long driverFee = order.getDriverFee() != null ? order.getDriverFee() : 0L; |
| | | |
| | | // 存件门店收益 |
| | | if (depositShopFee > 0 && order.getDepositShopId() != null) { |
| | | ShopInfo depositShop = shopInfoMapper.selectById(order.getDepositShopId()); |
| | | if (depositShop != null && depositShop.getRegionMemberId() != null) { |
| | | revenueMapper.insert(buildRevenue(depositShop.getRegionMemberId(), Constants.TWO, |
| | | depositShopFee, orderId, order.getCode())); |
| | | } |
| | | } |
| | | |
| | | // 取件门店收益(异地寄存且有取件门店) |
| | | if (takeShopFee > 0 && order.getTakeShopId() != null) { |
| | | ShopInfo takeShop = shopInfoMapper.selectById(order.getTakeShopId()); |
| | | if (takeShop != null && takeShop.getRegionMemberId() != null) { |
| | | revenueMapper.insert(buildRevenue(takeShop.getRegionMemberId(), Constants.TWO, |
| | | takeShopFee, orderId, order.getCode())); |
| | | } |
| | | } |
| | | |
| | | // 司机收益(异地寄存) |
| | | if (driverFee > 0 && order.getAcceptDriver() != null) { |
| | | DriverInfo driver = driverInfoMapper.selectById(order.getAcceptDriver()); |
| | | if (driver != null && driver.getMemberId() != null) { |
| | | revenueMapper.insert(buildRevenue(driver.getMemberId(), Constants.ONE, |
| | | driverFee, orderId, order.getCode())); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 构建收益记录 |
| | | */ |
| | | private Revenue buildRevenue(Integer memberId, Integer memberType, Long amount, Integer orderId, String orderNo) { |
| | | Revenue revenue = new Revenue(); |
| | | revenue.setMemberId(memberId); |
| | | revenue.setMemberType(memberType); // 1=司机, 2=门店 |
| | | revenue.setType(Constants.ZERO); // 0=完成订单 |
| | | revenue.setOptType(Constants.ONE); // 1=收入 |
| | | revenue.setAmount(amount); |
| | | revenue.setVaildStatus(Constants.ZERO); // 0=入账中(未结算) |
| | | revenue.setObjId(orderId); |
| | | revenue.setObjType(Constants.ZERO); // 0=订单业务 |
| | | revenue.setStatus(Constants.ZERO); // 0=成功 |
| | | revenue.setOrderNo(orderNo); |
| | | revenue.setDeleted(Constants.ZERO); |
| | | revenue.setCreateTime(new Date()); |
| | | return revenue; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void driverVerifyOrder(String verifyCode, List<String> images, String remark, Integer driverId) { |
| | | if (StringUtils.isBlank(verifyCode)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "核销码不能为空"); |
| | | } |
| | | // 根据司机核销码查找订单 |
| | | Orders order = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getDriverVerifyCode, verifyCode) |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (order == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "核销码无效"); |
| | | } |
| | | |
| | | // 仅异地寄存 + 有取件门店 + 派送中(4) 可核销 |
| | | if (!Constants.equalsInteger(order.getType(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅异地寄存订单支持司机核销"); |
| | | } |
| | | if (order.getTakeShopId() == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单无取件门店,无需司机核销"); |
| | | } |
| | | if (!Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.delivering.getStatus())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不允许核销"); |
| | | } |
| | | |
| | | // 派送中(4) → 已到店(5) |
| | | order.setStatus(Constants.OrderStatus.arrived.getStatus()); |
| | | order.setArriveTime(new Date()); |
| | | if (StringUtils.isNotBlank(remark)) { |
| | | order.setRemark(remark); |
| | | } |
| | | ordersMapper.updateById(order); |
| | | |
| | | // 释放司机核销码 |
| | | releaseVerifyCode(verifyCode); |
| | | |
| | | // 保存附件(obj_type=3 门店入库图片,最多3张) |
| | | saveVerifyImages(order.getId(), images, Constants.FileType.ORDER_TAKE.getKey(), driverId); |
| | | } |
| | | |
| | | /** |
| | | * 保存核销附件到 multifile 表 |
| | | * |
| | | * @param orderId 订单主键 |
| | | * @param images 图片地址列表(最多3张) |
| | | * @param objType 附件类型 |
| | | * @param creator 创建人编码 |
| | | */ |
| | | private void saveVerifyImages(Integer orderId, List<String> images, int objType, Integer creator) { |
| | | if (images == null || images.isEmpty()) return; |
| | | List<String> saveImages = images.size() > 3 ? images.subList(0, 3) : images; |
| | | Date now = new Date(); |
| | | int sortNum = 1; |
| | | for (String imgUrl : saveImages) { |
| | | if (StringUtils.isBlank(imgUrl)) continue; |
| | | Multifile multifile = new Multifile(); |
| | | multifile.setObjId(orderId); |
| | | multifile.setObjType(objType); |
| | | multifile.setFileurl(imgUrl); |
| | | multifile.setType(Constants.ZERO); |
| | | multifile.setCreator(creator); |
| | | multifile.setCreateDate(now); |
| | | multifile.setIsdeleted(Constants.ZERO); |
| | | multifile.setSortnum(sortNum++); |
| | | multifileMapper.insert(multifile); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = {Exception.class, BusinessException.class}) |
| | | public void confirmCustomerArrived(Integer orderId, Integer shopId) { |
| | | // 1. 查询订单 |
| | | Orders order = ordersMapper.selectById(orderId); |
| | | if (order == null || Constants.equalsInteger(order.getDeleted(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在"); |
| | | } |
| | | |
| | | // 2. 校验订单状态:待取件(5) |
| | | if (!Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.arrived.getStatus())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不允许该操作"); |
| | | } |
| | | |
| | | // 3. 校验门店与订单关系 |
| | | if (Constants.equalsInteger(order.getType(), Constants.ONE) && order.getTakeShopId() != null) { |
| | | // 异地寄存有取件门店:校验取件门店 |
| | | if (!shopId.equals(order.getTakeShopId())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单不属于当前门店"); |
| | | } |
| | | } else if (Constants.equalsInteger(order.getType(), Constants.ZERO)) { |
| | | // 就地寄存:校验存件门店(取件门店同存件门店) |
| | | if (!shopId.equals(order.getDepositShopId())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单不属于当前门店"); |
| | | } |
| | | } else { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单无取件门店,无法确认到店"); |
| | | } |
| | | |
| | | // 4. 查询门店名称(用于日志) |
| | | String shopName = ""; |
| | | ShopInfo shopInfo = shopInfoMapper.selectById(shopId); |
| | | if (shopInfo != null) { |
| | | shopName = shopInfo.getName() != null ? shopInfo.getName() : ""; |
| | | } |
| | | |
| | | // 5. 计算逾期费用 |
| | | List<OrdersDetail> details = ordersDetailMapper.selectList( |
| | | new QueryWrapper<OrdersDetail>().lambda() |
| | | .eq(OrdersDetail::getOrderId, orderId) |
| | | .eq(OrdersDetail::getDeleted, Constants.ZERO)); |
| | | OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(order, details); |
| | | |
| | | Date now = new Date(); |
| | | |
| | | if (overdueInfo.getOverdue() && overdueInfo.getOverdueDays() > 0) { |
| | | // 存在逾期:标记逾期状态,订单保持当前状态 |
| | | order.setConfirmArriveTime(now); |
| | | order.setOverdueStatus(Constants.ONE); |
| | | order.setOverdueDays(overdueInfo.getOverdueDays()); |
| | | order.setOverdueAmount(overdueInfo.getOverdueFee()); |
| | | order.setUpdateTime(now); |
| | | ordersMapper.updateById(order); |
| | | |
| | | // 记录订单日志 |
| | | saveShopVerifyLog(order, "确认顾客到店(逾期)", |
| | | "门店【" + shopName + "】确认顾客到店,逾期" + overdueInfo.getOverdueDays() |
| | | + "天,逾期费用" + Constants.getFormatMoney(overdueInfo.getOverdueFee()) + "元", |
| | | null, shopId); |
| | | } else { |
| | | // 未逾期:标记逾期状态为0,订单保持当前状态 |
| | | order.setConfirmArriveTime(now); |
| | | order.setOverdueStatus(Constants.ZERO); |
| | | |
| | | // 就地寄存:计算是否需要退款 |
| | | if (Constants.equalsInteger(order.getType(), Constants.ZERO) && !CollectionUtils.isEmpty(details)) { |
| | | int actualDays = calcActualDepositDays(now, order.getDepositTime()); |
| | | order.setDepositDays(actualDays); |
| | | |
| | | int estimatedDays = order.getEstimatedDepositDays() != null ? order.getEstimatedDepositDays() : 1; |
| | | int refundDays = estimatedDays - actualDays; |
| | | if (refundDays > 0) { |
| | | // 退款金额 = 退款天数 × Σ(物品单价 × 数量) |
| | | long dailyBaseFee = 0L; |
| | | for (OrdersDetail d : details) { |
| | | dailyBaseFee += (d.getUnitPrice() != null ? d.getUnitPrice() : 0L) |
| | | * (d.getNum() != null ? d.getNum() : 0); |
| | | } |
| | | long refundAmount = (long) refundDays * dailyBaseFee; |
| | | order.setRefundAmount(refundAmount); |
| | | } |
| | | } |
| | | |
| | | order.setUpdateTime(now); |
| | | ordersMapper.updateById(order); |
| | | |
| | | // 退款导致总金额变化,重算三方收益 |
| | | if (order.getRefundAmount() != null && order.getRefundAmount() > 0) { |
| | | long newTotal = (order.getTotalAmount() != null ? order.getTotalAmount() : 0L) - order.getRefundAmount(); |
| | | order.setTotalAmount(newTotal); |
| | | ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .eq(Orders::getId, orderId) |
| | | .set(Orders::getTotalAmount, newTotal)); |
| | | calculateAndSaveOrderFees(orderId); |
| | | } |
| | | |
| | | // 记录订单日志 |
| | | String logInfo = "门店【" + shopName + "】确认顾客到店,未逾期"; |
| | | if (order.getRefundAmount() != null && order.getRefundAmount() > 0) { |
| | | logInfo += ",需退款" + Constants.getFormatMoney(order.getRefundAmount()) + "元"; |
| | | } |
| | | saveShopVerifyLog(order, "确认顾客到店", logInfo, null, shopId); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 构建订单状态描述 |
| | | */ |
| | | private String buildStatusDesc(Orders order) { |
| | | boolean isLocal = Constants.equalsInteger(order.getType(), Constants.ZERO); |
| | | Integer status = order.getStatus(); |
| | | if (status == null) return ""; |
| | | |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.waitPay.getStatus())) { |
| | | String minutes = ""; |
| | | try { |
| | | minutes = operationConfigBiz.getConfig().getAutoCancelTime(); |
| | | } catch (Exception ignored) {} |
| | | return "请在" + (StringUtils.isNotBlank(minutes) ? minutes : "") + "分钟内完成支付,超时订单将自动取消"; |
| | | } |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.waitDeposit.getStatus())) { |
| | | return isLocal ? "订单已支付,请等待门店确认接单" : "订单已支付,请等待门店确认接单"; |
| | | } |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.deposited.getStatus())) { |
| | | return isLocal ? "行李已寄存,请凭取件码前往指定门店取件" : "门店已接单,正在为您安排取件司机"; |
| | | } |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.accepted.getStatus())) { |
| | | return isLocal ? "行李已寄存,请凭取件码前往指定门店取件" : "已有司机抢单,正前往取件地点"; |
| | | } |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.delivering.getStatus())) { |
| | | return "司机已取件,正运往目的地"; |
| | | } |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.arrived.getStatus())) { |
| | | return "行李已送达服务点,请及时前往取件"; |
| | | } |
| | | if (Constants.equalsInteger(status, Constants.OrderStatus.finished.getStatus())) { |
| | | if (Constants.equalsInteger(order.getCommentStatus(), Constants.ONE)) { |
| | | return "感谢您的用心评价,祝您出行顺利,旅途愉快!"; |
| | | } |
| | | return "订单已完成,感谢您的支持,请对本次服务做出评价"; |
| | | } |
| | | 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 ""; |
| | | } |
| | | |
| | | /** |
| | | * 计算支付倒计时毫秒 |
| | | */ |
| | | private Long calcPayCountdownMs(Orders order) { |
| | | try { |
| | | String minutesStr = operationConfigBiz.getConfig().getAutoCancelTime(); |
| | | if (StringUtils.isBlank(minutesStr)) return -1L; |
| | | int minutes = Integer.parseInt(minutesStr); |
| | | long deadline = order.getCreateTime().getTime() + minutes * 60 * 1000L; |
| | | long remaining = deadline - System.currentTimeMillis(); |
| | | return remaining > 0 ? remaining : -1L; |
| | | } catch (Exception e) { |
| | | return -1L; |
| | | } |
| | | } |
| | | public OverdueFeeVO calculateOverdueFee(Integer orderId) { |
| | | Orders order = ordersMapper.selectById(orderId); |
| | | if (order == null || Constants.equalsInteger(order.getDeleted(), Constants.ONE)) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | |
| | | // 查询订单明细 |
| | | List<OrdersDetail> details = ordersDetailMapper.selectList( |
| | | new QueryWrapper<OrdersDetail>().lambda() |
| | | .eq(OrdersDetail::getOrderId, orderId) |
| | | .eq(OrdersDetail::getDeleted, Constants.ZERO)); |
| | | |
| | | return calculateOverdueFeeInternal(order, details); |
| | | } |
| | | |
| | | /** |
| | | * 逾期费用内部计算(不查库,接受预查询的数据) |
| | | * 供分页等已查询明细的业务场景复用,避免重复查询 |
| | | */ |
| | | private OverdueFeeVO calculateOverdueFeeInternal(Orders order, List<OrdersDetail> details) { |
| | | if (CollectionUtils.isEmpty(details)) { |
| | | OverdueFeeVO vo = new OverdueFeeVO(); |
| | | vo.setOverdue(false); |
| | | vo.setOverdueDays(0); |
| | | vo.setOverdueFee(0L); |
| | | vo.setDailyBaseFee(0L); |
| | | return vo; |
| | | } |
| | | |
| | | // 物品基础日费用 = Σ(单价 × 数量) |
| | | long dailyBaseFee = 0L; |
| | | for (OrdersDetail d : details) { |
| | | dailyBaseFee += (d.getUnitPrice() != null ? d.getUnitPrice() : 0L) |
| | | * (d.getNum() != null ? d.getNum() : 0); |
| | | } |
| | | |
| | | Date now = new Date(); |
| | | int overdueDays; |
| | | long overdueFee; |
| | | |
| | | if (Constants.equalsInteger(order.getType(), Constants.ZERO)) { |
| | | // ========== 就地寄存 ========== |
| | | overdueDays = calcLocalOverdueDays(now, order.getExpectedTakeTime()); |
| | | overdueFee = (long) overdueDays * dailyBaseFee; |
| | | |
| | | OverdueFeeVO vo = new OverdueFeeVO(); |
| | | vo.setOverdue(overdueDays > 0); |
| | | vo.setOverdueDays(overdueDays); |
| | | vo.setOverdueFee(overdueFee); |
| | | vo.setDailyBaseFee(dailyBaseFee); |
| | | return vo; |
| | | |
| | | } else { |
| | | // ========== 异地寄存 ========== |
| | | // 条件:存在取件门店 且 订单处于已到店状态(5) |
| | | if (order.getTakeShopId() == null |
| | | || !Constants.equalsInteger(order.getStatus(), Constants.FIVE)) { |
| | | OverdueFeeVO vo = new OverdueFeeVO(); |
| | | vo.setOverdue(false); |
| | | vo.setOverdueDays(0); |
| | | vo.setOverdueFee(0L); |
| | | vo.setDailyBaseFee(dailyBaseFee); |
| | | vo.setDiscountRate(null); |
| | | return vo; |
| | | } |
| | | |
| | | overdueDays = calcRemoteOverdueDays(now, order.getArriveTime()); |
| | | |
| | | // 折扣比率 |
| | | String discountStr = operationConfigBiz.getConfig().getUnpickedDiscount(); |
| | | BigDecimal discountRate = StringUtils.isNotBlank(discountStr) |
| | | ? new BigDecimal(discountStr) : BigDecimal.ONE; |
| | | |
| | | overdueFee = new BigDecimal(overdueDays) |
| | | .multiply(new BigDecimal(dailyBaseFee)) |
| | | .multiply(discountRate) |
| | | .setScale(0, RoundingMode.HALF_UP) |
| | | .longValue(); |
| | | |
| | | OverdueFeeVO vo = new OverdueFeeVO(); |
| | | vo.setOverdue(overdueDays > 0); |
| | | vo.setOverdueDays(overdueDays); |
| | | vo.setOverdueFee(overdueFee); |
| | | vo.setDailyBaseFee(dailyBaseFee); |
| | | vo.setDiscountRate(discountStr); |
| | | return vo; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 计算实际寄存天数(depositTime 到 now 的天数差,最少1天) |
| | | */ |
| | | private int calcActualDepositDays(Date now, Date depositTime) { |
| | | if (depositTime == null || now == null) { |
| | | return 1; |
| | | } |
| | | Calendar depositCal = Calendar.getInstance(); |
| | | depositCal.setTime(depositTime); |
| | | depositCal.set(Calendar.HOUR_OF_DAY, 0); |
| | | depositCal.set(Calendar.MINUTE, 0); |
| | | depositCal.set(Calendar.SECOND, 0); |
| | | depositCal.set(Calendar.MILLISECOND, 0); |
| | | |
| | | Calendar nowCal = Calendar.getInstance(); |
| | | nowCal.setTime(now); |
| | | nowCal.set(Calendar.HOUR_OF_DAY, 0); |
| | | nowCal.set(Calendar.MINUTE, 0); |
| | | nowCal.set(Calendar.SECOND, 0); |
| | | nowCal.set(Calendar.MILLISECOND, 0); |
| | | |
| | | long diffMs = nowCal.getTimeInMillis() - depositCal.getTimeInMillis(); |
| | | int days = (int) (diffMs / (1000 * 60 * 60 * 24)); |
| | | return Math.max(days, 1); |
| | | } |
| | | |
| | | /** |
| | | * 就地寄存逾期天数计算 |
| | | * 过了预计取件时间当天的12点后才算一天 |
| | | */ |
| | | private int calcLocalOverdueDays(Date now, Date expectedTakeTime) { |
| | | if (expectedTakeTime == null || !now.after(expectedTakeTime)) { |
| | | return 0; |
| | | } |
| | | // 基准时间 = 预计取件日期的12:00 |
| | | Calendar baseCal = Calendar.getInstance(); |
| | | baseCal.setTime(expectedTakeTime); |
| | | baseCal.set(Calendar.HOUR_OF_DAY, 12); |
| | | 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.MINUTE, 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); |
| | | } |
| | | |
| | | /** |
| | | * 异地寄存逾期天数计算 |
| | | * 过了转移到店时间当天的晚上12点(24:00)后才算第一天 |
| | | */ |
| | | private int calcRemoteOverdueDays(Date now, Date arriveTime) { |
| | | if (arriveTime == null || !now.after(arriveTime)) { |
| | | 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.MINUTE, 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); |
| | | } |
| | | |
| | | } |