| | |
| | | import com.stylefeng.guns.modular.system.util.*; |
| | | import com.stylefeng.guns.modular.taxi.model.OrderTaxi; |
| | | import com.stylefeng.guns.modular.taxi.service.IOrderTaxiService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.data.redis.core.RedisTemplate; |
| | |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.util.*; |
| | | |
| | | |
| | | @Slf4j |
| | | @Service |
| | | public class OrderPrivateCarServiceImpl extends ServiceImpl<OrderPrivateCarMapper, OrderPrivateCar> implements IOrderPrivateCarService { |
| | | |
| | |
| | | List<Map<String, Object>> order = this.baseMapper.queryOrderInfo(orderId,4,null,null); |
| | | for (Map<String, Object> map : order) { |
| | | String phone = map.get("phone").toString(); |
| | | String s = phone.substring(0, 3) + "xxxx" + phone.substring(7 ); |
| | | String s = phone.substring(0, 3) + "****" + phone.substring(7 ); |
| | | map.put("realPhone", s); |
| | | } |
| | | if(order!=null){ |
| | |
| | | map.put("canOperation",canOperation); |
| | | System.out.println(map); |
| | | String phone = map.get("phone").toString(); |
| | | String s = phone.substring(0, 3) + "xxxx" + phone.substring(7 ); |
| | | String s = phone.substring(0, 3) + "****" + phone.substring(7 ); |
| | | map.put("realPhone", s); |
| | | return map; |
| | | } |
| | |
| | | return ResultUtil.error("当前订单不能操作"); |
| | | } |
| | | } |
| | | Driver driver = driverService.selectById(orderPrivateCar.getDriverId()); |
| | | switch (state){ |
| | | case 3://出发前往预约点 |
| | | orderPrivateCar.setState(3); |
| | | orderPrivateCar.setSetOutTime(new Date()); |
| | | if (driver.getState() != 3) { |
| | | driver.setState(3); |
| | | driverService.updateById(driver); |
| | | } |
| | | systemNoticeService.addSystemNotice(1, "司机已出发,请耐心等待", orderPrivateCar.getUserId(), 1); |
| | | break; |
| | | case 4://到达预约点,等待客户上车 |
| | |
| | | orderPrivateCar.setGetoffAddress(address); |
| | | orderPrivateCar.setGetoffTime(new Date()); |
| | | orderPrivateCar.setEndServiceTime(new Date()); |
| | | if (driver.getState() != 2) { |
| | | driver.setState(2); |
| | | driverService.updateById(driver); |
| | | } |
| | | break; |
| | | } |
| | | orderPrivateCar.setCancelType(2); |
| | | this.updateById(orderPrivateCar); |
| | | |
| | | // TODO: 2020/6/5 推送状态 |
| | | // 待处理:2020/6/5 推送状态 |
| | | OrderPrivateCar finalOrderPrivateCar = orderPrivateCar; |
| | | new Thread(new Runnable() { |
| | | @Override |
| | |
| | | } |
| | | } |
| | | }).start(); |
| | | return ResultUtil.success(); |
| | | } |
| | | |
| | | @Override |
| | | public ResultUtil setDestination(Integer orderId, Integer uid, Double endLon, Double endLat, String endAddress) throws Exception { |
| | | // 只允许快捷叫车订单在服务中由接单司机设置终点。 |
| | | if (orderId == null || endLon == null || endLat == null || ToolUtil.isEmpty(endAddress)) { |
| | | return ResultUtil.error("请设置终点"); |
| | | } |
| | | OrderPrivateCar orderPrivateCar = this.selectById(orderId); |
| | | if (orderPrivateCar == null) { |
| | | return ResultUtil.error("订单不存在"); |
| | | } |
| | | if (!Integer.valueOf(2).equals(orderPrivateCar.getCallType())) { |
| | | return ResultUtil.error("非快捷叫车订单不能设置终点"); |
| | | } |
| | | if (!Integer.valueOf(uid).equals(orderPrivateCar.getDriverId())) { |
| | | return ResultUtil.error("只能操作本司机订单"); |
| | | } |
| | | if (!Integer.valueOf(5).equals(orderPrivateCar.getState())) { |
| | | return ResultUtil.error("乘客上车后才能设置终点"); |
| | | } |
| | | endAddress = endAddress.replaceAll("& #40;", "("); |
| | | endAddress = endAddress.replaceAll("& #41;", ")"); |
| | | orderPrivateCar.setEndLon(endLon); |
| | | orderPrivateCar.setEndLat(endLat); |
| | | orderPrivateCar.setEndAddress(endAddress); |
| | | // 设置终点后补算预估里程和时间,方便司机端、用户端和管理端展示。 |
| | | if (orderPrivateCar.getStartLon() != null && orderPrivateCar.getStartLat() != null) { |
| | | Map<String, String> distanceMap = gdMapElectricFenceUtil.getDistance(orderPrivateCar.getStartLon() + "," + orderPrivateCar.getStartLat(), endLon + "," + endLat, 1); |
| | | orderPrivateCar.setEstimateMileage(Double.valueOf(distanceMap.get("distance"))); |
| | | orderPrivateCar.setEstimateTime(Double.valueOf(distanceMap.get("duration")) / 60); |
| | | } |
| | | this.updateById(orderPrivateCar); |
| | | pushUtil.pushOrderState(1, orderPrivateCar.getUserId(), orderPrivateCar.getId(), 1, orderPrivateCar.getState()); |
| | | pushUtil.pushOrderState(2, orderPrivateCar.getDriverId(), orderPrivateCar.getId(), 1, orderPrivateCar.getState()); |
| | | return ResultUtil.success(); |
| | | } |
| | | |
| | |
| | | return; |
| | | } |
| | | |
| | | PaymentRecord paymentRecord = paymentRecordService.query(1, orderPrivateCar.getUserId(), 1, orderPrivateCar.getId(), 1, orderPrivateCar.getPayType(), 2); |
| | | if (paymentRecord == null || ToolUtil.isEmpty(paymentRecord.getCode())) { |
| | | System.err.println("预支付退款数据异常(privateCarOrderId = " + orderPrivateCar.getId() + ")"); |
| | | return; |
| | | } |
| | | |
| | | if (Integer.valueOf(1).equals(orderPrivateCar.getPayType())) { |
| | | Map<String, String> map = payMoneyUtil.wxRefund(paymentRecord.getCode(), refundNo, paymentRecord.getAmount().toString(), refundMoney.toString(), "/base/prepayRefundWXPay"); |
| | | if (!"SUCCESS".equals(map.get("return_code"))) { |
| | | System.err.println("专车预支付退款申请失败:" + map.get("return_msg")); |
| | | String outRequestNo = orderPrivateCar.getPrepaySecondPayNo(); |
| | | if (ToolUtil.isEmpty(outRequestNo)) { |
| | | System.err.println("快车微信先付订单缺少支付单号,无法关闭支付单(privateCarOrderId = " + orderPrivateCar.getId() + ")"); |
| | | return; |
| | | } |
| | | CbyzxPayUtil.ClosePayOrderRequest request = new CbyzxPayUtil.ClosePayOrderRequest(); |
| | | request.setOutRequestNo(outRequestNo); |
| | | request.setRefundOutRequestNo(refundNo); |
| | | request.setRefundAmount(toFen(refundMoney)); |
| | | request.setRefundDesc("快车预支付多退退款"); |
| | | JSONObject response = CbyzxPayUtil.closePayOrder(request); |
| | | if (isPrepayRefundSuccess(response)) { |
| | | String responseRefundNo = extractPrepayRefundNo(response); |
| | | if (ToolUtil.isNotEmpty(responseRefundNo)) { |
| | | orderPrivateCar.setPrepayRefundNo(responseRefundNo); |
| | | } |
| | | finishPrepaidOrder(orderPrivateCar); |
| | | } else { |
| | | System.err.println("快车微信先付退款申请失败:" + extractPrepayRefundMessage(response)); |
| | | } |
| | | return; |
| | | } |
| | | |
| | | if (Integer.valueOf(2).equals(orderPrivateCar.getPayType())) { |
| | | PaymentRecord paymentRecord = paymentRecordService.query(1, orderPrivateCar.getUserId(), 1, orderPrivateCar.getId(), 1, orderPrivateCar.getPayType(), 2); |
| | | if (paymentRecord == null || ToolUtil.isEmpty(paymentRecord.getCode())) { |
| | | System.err.println("预支付退款数据异常(privateCarOrderId = " + orderPrivateCar.getId() + ")"); |
| | | return; |
| | | } |
| | | try { |
| | | Map<String, String> map = payMoneyUtil.aliRefund(paymentRecord.getCode(), refundMoney.toString()); |
| | | if ("10000".equals(map.get("code"))) { |
| | |
| | | |
| | | private String buildPrepayRefundNo(Integer orderType, Integer orderId) { |
| | | return "PRF_" + orderType + "_" + orderId + "_" + System.currentTimeMillis(); |
| | | } |
| | | |
| | | private Integer toFen(Double amount) { |
| | | return new BigDecimal(String.valueOf(amount)).multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).intValue(); |
| | | } |
| | | |
| | | private boolean isPrepayRefundSuccess(JSONObject response) { |
| | | if (response == null) { |
| | | return false; |
| | | } |
| | | Object code = response.get("code"); |
| | | if (code == null || !"0".equals(String.valueOf(code))) { |
| | | return false; |
| | | } |
| | | JSONObject data = response.getJSONObject("data"); |
| | | return data != null && Boolean.TRUE.equals(data.getBoolean("isSuccess")); |
| | | } |
| | | |
| | | private String extractPrepayRefundNo(JSONObject response) { |
| | | if (response == null) { |
| | | return null; |
| | | } |
| | | JSONObject data = response.getJSONObject("data"); |
| | | if (data == null) { |
| | | return null; |
| | | } |
| | | String refundNo = data.getString("merchantRefundSerialNo"); |
| | | if (ToolUtil.isNotEmpty(refundNo)) { |
| | | return refundNo; |
| | | } |
| | | refundNo = data.getString("refundId"); |
| | | if (ToolUtil.isNotEmpty(refundNo)) { |
| | | return refundNo; |
| | | } |
| | | return data.getString("gatewaySerialNo"); |
| | | } |
| | | |
| | | private String extractPrepayRefundMessage(JSONObject response) { |
| | | if (response == null) { |
| | | return "微信先付退款失败"; |
| | | } |
| | | JSONObject data = response.getJSONObject("data"); |
| | | if (data != null && ToolUtil.isNotEmpty(data.getString("failReason"))) { |
| | | return data.getString("failReason"); |
| | | } |
| | | String msg = response.getString("msg"); |
| | | return ToolUtil.isNotEmpty(msg) ? msg : "微信先付退款失败"; |
| | | } |
| | | |
| | | private Double formatMoney(Double money) { |
| | |
| | | |
| | | Map<String, Object> map = new HashMap<>(); |
| | | if(orderPrivateCar.getState() == 5){ |
| | | map.put("orderMoney", orderPrivateCar.getOrderMoney()==null?0:orderPrivateCar.getOrderMoney());//订单金额 |
| | | map.put("orderMoney", orderPrivateCar.getOrderMoney()==null?BigDecimal.ZERO:new BigDecimal(orderPrivateCar.getOrderMoney().toString()).setScale(2,RoundingMode.HALF_UP));//订单金额 |
| | | }else{ |
| | | if(orderPrivateCar.getAbnormal() == 2 && orderPrivateCar.getResponsibilityType() > 2 && orderPrivateCar.getAbnormalStatus() == 2){ |
| | | map.put("orderMoney", orderPrivateCar.getResponsibilityMoney()); |
| | | }else{ |
| | | map.put("orderMoney", orderPrivateCar.getOrderMoney()==null?0:orderPrivateCar.getOrderMoney());//订单金额 |
| | | map.put("orderMoney", orderPrivateCar.getOrderMoney()==null?BigDecimal.ZERO:new BigDecimal(orderPrivateCar.getOrderMoney().toString()).setScale(2,RoundingMode.HALF_UP));//订单金额 |
| | | } |
| | | } |
| | | map.put("startMileage", orderPrivateCar.getStartMileage());//起步价 |
| | |
| | | double estimateMileage = (null == orderPrivateCar.getEstimateMileage() ? 0D : orderPrivateCar.getEstimateMileage()); |
| | | System.out.println("预估里程数"+estimateMileage); |
| | | //在价格区间按照一口价算,不在区间按实时价格算 |
| | | if(d<estimateMileage+contentPrice.getDouble("num29")*1000 && d>estimateMileage-contentPrice.getDouble("num32")*1000){ |
| | | double exceedMileageInner = Optional.ofNullable(query1.get("exceedMileageInner")).map(Object::toString).map(Double::parseDouble).orElse(0d); |
| | | double belowMileageInner = Optional.ofNullable(query1.get("belowMileageInner")).map(Object::toString).map(Double::parseDouble).orElse(0d); |
| | | if(d<estimateMileage+exceedMileageInner*1000 && d>estimateMileage-belowMileageInner*1000) { |
| | | System.out.println("在区间==============="); |
| | | orderPrivateCar = calculationPrice1(orderPrivateCar,contentPrice,jsonObject.getLongValue("num1"),jsonObject.getDouble("num2"),parkingFee,crossingFee); |
| | | orderPrivateCar = calculationPrice(orderPrivateCar,contentPrice,jsonObject.getLongValue("num1"),jsonObject.getDouble("num2"),parkingFee,crossingFee); |
| | | System.out.println("返回订单数据"+orderPrivateCar); |
| | | }else{ |
| | | System.out.println("不在区间===================="); |
| | |
| | | return orderPrivateCar; |
| | | } |
| | | |
| | | /** |
| | | * sky |
| | | * 公共费用计算 |
| | | * @param orderPrivateCar |
| | | * @param rule 计费规则 |
| | | * @param wait 规则-等待时长 |
| | | * @param waitMoney 规则-等待单价 |
| | | * @param parkingFee 停车费 |
| | | * @param crossingFee 过路费 |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | public OrderPrivateCar calculationPrice(OrderPrivateCar orderPrivateCar, JSONObject rule, |
| | | long wait, Double waitMoney, |
| | | Double parkingFee, Double crossingFee) throws Exception { |
| | | orderPrivateCar.setChargeRule(rule.toJSONString()); |
| | | |
| | | Date date = new Date(); |
| | | if (orderPrivateCar.getEndServiceTime() == null) { |
| | | orderPrivateCar.setEndServiceTime(date); |
| | | } |
| | | |
| | | double d = (orderPrivateCar.getMileage() == null ? 0D : orderPrivateCar.getMileage()) / 1000; |
| | | double t = ((orderPrivateCar.getEndServiceTime().getTime() |
| | | - orderPrivateCar.getStartServiceTime().getTime()) / 60000) + 1; |
| | | double d1 = Math.max(0, d - rule.getDouble("num2")); |
| | | double t1 = Math.max(0, t - rule.getDouble("num3")); |
| | | |
| | | double w = ((orderPrivateCar.getStartServiceTime().getTime() |
| | | - orderPrivateCar.getArriveTime().getTime()) / 60000) + 1; |
| | | double w1 = (w - wait) < 0 ? 0 |
| | | : new BigDecimal(w - wait).setScale(0, BigDecimal.ROUND_UP).doubleValue(); |
| | | |
| | | // 从 num14 开始,每 7 个为一组:numI=时间区间, +1=起步价, +2=里程费率, |
| | | // +3=时长费率, +4=远途1费率, +5=远途2费率, +6=远途3费率 |
| | | int startIndex = 14; |
| | | boolean matched = false; |
| | | |
| | | while (rule.containsKey("num" + startIndex)) { |
| | | // 必须保证后续 6 个参数都存在 |
| | | if (!rule.containsKey("num" + (startIndex + 6))) { |
| | | break; |
| | | } |
| | | |
| | | String timeRange = rule.getString("num" + startIndex); |
| | | // 兼容 "HH:mm - HH:mm" 和 "HH:mm-HH:mm" 两种格式 |
| | | String[] parts = timeRange.split("\\s*-\\s*"); |
| | | if (parts.length != 2) { |
| | | startIndex += 7; |
| | | continue; |
| | | } |
| | | |
| | | try { |
| | | Calendar rangeStart = parseTimeToCalendar(date, parts[0].trim()); |
| | | Calendar rangeEnd = parseTimeToCalendar(date, parts[1].trim()); |
| | | // 跨天处理(如 "20:00 - 02:00") |
| | | if (rangeStart.getTimeInMillis() > rangeEnd.getTimeInMillis()) { |
| | | rangeEnd.add(Calendar.DAY_OF_YEAR, 1); |
| | | } |
| | | |
| | | boolean inRange = date.getTime() > rangeStart.getTimeInMillis() |
| | | && date.getTime() < rangeEnd.getTimeInMillis(); |
| | | |
| | | if (inRange) { |
| | | double qibujia = rule.getDouble("num" + (startIndex + 1)); |
| | | double lchengLv = rule.getDouble("num" + (startIndex + 2)); |
| | | double schangLv = rule.getDouble("num" + (startIndex + 3)); |
| | | double yt1Lv = rule.getDouble("num" + (startIndex + 4)); |
| | | double yt2Lv = rule.getDouble("num" + (startIndex + 5)); |
| | | double yt3Lv = rule.getDouble("num" + (startIndex + 6)); |
| | | |
| | | applyPricing(orderPrivateCar, rule, d, d1, t1, w1, |
| | | waitMoney, parkingFee, crossingFee, |
| | | qibujia, lchengLv, schangLv, yt1Lv, yt2Lv, yt3Lv); |
| | | matched = true; |
| | | break; |
| | | } |
| | | } catch (Exception e) { |
| | | // 时间解析异常时跳过该组,继续匹配下一组 |
| | | } |
| | | |
| | | startIndex += 7; |
| | | } |
| | | |
| | | // 无任何时间组匹配,使用基础费率(num1 ~ num13) |
| | | if (!matched) { |
| | | applyPricing(orderPrivateCar, rule, d, d1, t1, w1, |
| | | waitMoney, parkingFee, crossingFee, |
| | | rule.getDouble("num1"), |
| | | rule.getDouble("num4"), |
| | | rule.getDouble("num5"), |
| | | rule.getDouble("num8"), |
| | | rule.getDouble("num11"), |
| | | rule.getDouble("num13")); |
| | | } |
| | | |
| | | return orderPrivateCar; |
| | | } |
| | | |
| | | /** |
| | | * sky |
| | | * 将 "HH:mm" 解析为基于 baseDate 当天的 Calendar |
| | | */ |
| | | private Calendar parseTimeToCalendar(Date baseDate, String hhmm) { |
| | | String[] hm = hhmm.split(":"); |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(baseDate); |
| | | cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hm[0])); |
| | | cal.set(Calendar.MINUTE, Integer.parseInt(hm[1])); |
| | | cal.set(Calendar.SECOND, 0); |
| | | cal.set(Calendar.MILLISECOND, 0); |
| | | return cal; |
| | | } |
| | | |
| | | /** |
| | | * sky |
| | | * 按指定费率计算远途费、各项费用,并写入 orderPrivateCar |
| | | * |
| | | * 远途分段逻辑(与原代码保持一致): |
| | | * 段1:num6 < d < num7 → yt1 = yt1Lv * d |
| | | * 段2:num9 < d < num10 → yt1 = yt1Lv * num7, yt2 = yt2Lv * (d - num9) |
| | | * 段3:d > num12 → yt1 = yt1Lv * num7, yt2 = yt2Lv * (num10 - num9), yt3 = yt3Lv * (d - num12) |
| | | */ |
| | | private void applyPricing(OrderPrivateCar orderPrivateCar, JSONObject rule, |
| | | double d, double d1, double t1, double w1, |
| | | Double waitMoney, Double parkingFee, Double crossingFee, |
| | | double qibujia, double lchengLv, double schangLv, |
| | | double yt1Lv, double yt2Lv, double yt3Lv) { |
| | | |
| | | double num6 = rule.getDouble("num6"); |
| | | double num7 = rule.getDouble("num7"); |
| | | double num9 = rule.getDouble("num9"); |
| | | double num10 = rule.getDouble("num10"); |
| | | double num12 = rule.getDouble("num12"); |
| | | |
| | | double yt1 = 0, yt2 = 0, yt3 = 0; |
| | | |
| | | if (d > num6 && d < num7) { |
| | | yt1 = yt1Lv * d; |
| | | } |
| | | if (d > num9 && d < num10) { |
| | | yt1 = yt1Lv * num7; |
| | | yt2 = yt2Lv * (d - num9); |
| | | } |
| | | if (d > num12) { |
| | | yt1 = yt1Lv * num7; |
| | | yt2 = yt2Lv * (num10 - num9); |
| | | yt3 = yt3Lv * (d - num12); |
| | | } |
| | | |
| | | double mileageMoney = new BigDecimal(d1 * lchengLv).setScale(2, BigDecimal.ROUND_DOWN).doubleValue(); |
| | | double durationMoney = new BigDecimal(t1 * schangLv).setScale(2, BigDecimal.ROUND_DOWN).doubleValue(); |
| | | double waitMoneyAmt = new BigDecimal(w1 * waitMoney).setScale(2, BigDecimal.ROUND_DOWN).doubleValue(); |
| | | double longDistMoney = new BigDecimal(yt1 + yt2 + yt3).setScale(2, BigDecimal.ROUND_DOWN).doubleValue(); |
| | | |
| | | orderPrivateCar.setStartMileage(rule.getDouble("num2")); |
| | | orderPrivateCar.setStartMoney(qibujia); |
| | | orderPrivateCar.setMileageKilometers(new BigDecimal(d1).setScale(2, BigDecimal.ROUND_HALF_EVEN).doubleValue()); |
| | | orderPrivateCar.setMileageMoney(mileageMoney); |
| | | orderPrivateCar.setDuration(new BigDecimal(t1).setScale(2, BigDecimal.ROUND_HALF_EVEN).doubleValue()); |
| | | orderPrivateCar.setDurationMoney(durationMoney); |
| | | orderPrivateCar.setWait(new BigDecimal(w1).setScale(2, BigDecimal.ROUND_HALF_EVEN).doubleValue()); |
| | | orderPrivateCar.setWaitMoney(waitMoneyAmt); |
| | | orderPrivateCar.setLongDistance(new BigDecimal(d > num6 ? d - num6 : 0).setScale(2, BigDecimal.ROUND_HALF_EVEN).doubleValue()); |
| | | orderPrivateCar.setLongDistanceMoney(longDistMoney); |
| | | orderPrivateCar.setParkMoney(parkingFee); |
| | | orderPrivateCar.setRoadTollMoney(crossingFee); |
| | | orderPrivateCar.setRedPacketMoney(0D); |
| | | orderPrivateCar.setCouponMoney(0D); |
| | | orderPrivateCar.setDiscount(0D); |
| | | orderPrivateCar.setPayMoney(0D); |
| | | |
| | | double amount = qibujia + mileageMoney + durationMoney + waitMoneyAmt + longDistMoney; |
| | | orderPrivateCar.setOrderMoney(amount + parkingFee + crossingFee); |
| | | } |
| | | |
| | | /** |
| | | * 公共费用计算 |
| | |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | public OrderPrivateCar calculationPrice(OrderPrivateCar orderPrivateCar,JSONObject rule, long wait,Double waitMoney, Double parkingFee, Double crossingFee) throws Exception { |
| | | @Deprecated |
| | | public OrderPrivateCar calculationPriceBack(OrderPrivateCar orderPrivateCar,JSONObject rule, long wait,Double waitMoney, Double parkingFee, Double crossingFee) throws Exception { |
| | | orderPrivateCar.setChargeRule(rule.toJSONString()); |
| | | double amount = 0.0; |
| | | //等待费 |