| | |
| | | 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 java.math.RoundingMode; |
| | | import java.util.*; |
| | | |
| | | |
| | | @Slf4j |
| | | @Service |
| | | public class OrderPrivateCarServiceImpl extends ServiceImpl<OrderPrivateCarMapper, OrderPrivateCar> implements IOrderPrivateCarService { |
| | | |
| | |
| | | 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) { |
| | |
| | | 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; |
| | | //等待费 |