From 266742ca2dd87b9300b340f40c23a585dc35a7d3 Mon Sep 17 00:00:00 2001 From: "925116093-qq.com" <925116093@qq.com> Date: Fri, 20 Jun 2025 14:51:06 +0800 Subject: [PATCH] 202506201451 --- .../system/controller/AppletController.java | 733 ++++++++++---- .../ruoyi/system/controller/CoursorUtil.java | 291 +++--- .../controller/PayNotifyController.java | 949 ++++++++++++++++++ .../controllerUtil/AppletControllerUtil.java | 109 +- .../controllerUtil/OrderBindWorkerUtil.java | 1 + .../system/controllerUtil/WXsendMsgUtil.java | 48 + .../system/controllerUtil/WechatPayUtil.java | 154 ++- .../java/com/ruoyi/system/domain/Order.java | 4 +- .../ruoyi/system/mapper/SiteConfigMapper.java | 2 + .../system/mapper/WorkerLevelMapper.java | 3 + .../system/service/ISiteConfigService.java | 2 +- .../system/service/IWorkerLevelService.java | 2 +- .../service/impl/SiteConfigServiceImpl.java | 5 + .../service/impl/WorkerLevelServiceImpl.java | 5 + .../mapper/system/OrderLogMapper.xml | 2 +- .../mapper/system/SiteConfigMapper.xml | 4 + .../mapper/system/WorkerLevelMapper.xml | 4 + 17 files changed, 1966 insertions(+), 352 deletions(-) create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/controller/PayNotifyController.java diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppletController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppletController.java index d711cdf..5c11b44 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppletController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppletController.java @@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; +import java.text.DateFormat; import java.util.*; import java.text.SimpleDateFormat; import java.util.stream.Collectors; @@ -977,7 +978,12 @@ public class AppletController extends BaseController { orderData.put("status_text", getOrderStatusText(order.getStatus())); // 状态文本 orderData.put("total_price", order.getTotalPrice() != null ? order.getTotalPrice().toString() : "0.00"); orderData.put("num", order.getNum()); - orderData.put("sku", order.getSku()); + if (order.getSku()!=null) { + orderData.put("sku", order.getSku()); + } else { + orderData.put("sku", null); + } + // 时间字段格式化 if (order.getPayTime() != null) { @@ -1472,7 +1478,8 @@ public class AppletController extends BaseController { } // 其他业务字段 - userInfo.put("commission", user.getCommission().toString() != null ? user.getCommission().toString() : "0.00"); + userInfo.put("commission","0.00"); + //userInfo.put("commission", user.getCommission().toString() != null ? user.getCommission().toString() : "0.00"); userInfo.put("integral", user.getIntegral() != null ? user.getIntegral() : 0); userInfo.put("is_stop", user.getIsStop() != null ? user.getIsStop() : 1); userInfo.put("job_number", user.getJobNumber()); @@ -1487,7 +1494,8 @@ public class AppletController extends BaseController { userInfo.put("remember_token", user.getRememberToken()); userInfo.put("status", user.getStatus() != null ? user.getStatus() : 1); userInfo.put("tpd", 0); // 默认值 - userInfo.put("total_comm", user.getTotalComm().toString() != null ? user.getTotalComm().toString() : "0.00"); + userInfo.put("total_comm","0.00"); + // userInfo.put("total_comm", user.getTotalComm().toString() != null ? user.getTotalComm().toString() : "0.00"); userInfo.put("total_integral", user.getTotalIntegral() != null ? user.getTotalIntegral() : 100); userInfo.put("type", user.getType() != null ? user.getType().toString() : "1"); userInfo.put("worker_time", user.getWorkerTime()); @@ -3667,8 +3675,25 @@ public class AppletController extends BaseController { } // 4. 获取商品规格参数 - String sku = params.get("sku") != null ? params.get("sku").toString().trim() : ""; - + // String sku = params.get("sku") != null ? params.get("sku").toString().trim() : ""; + String sku = null; + if (params.get("sku") != null) { + Object skuParam = params.get("sku"); + if (skuParam instanceof Map) { + // 如果前端传递的是Map对象,转换为JSON字符串 + try { + sku = com.alibaba.fastjson2.JSON.toJSONString(skuParam); + } catch (Exception e) { + System.err.println("SKU转换JSON失败:" + e.getMessage()); + sku = skuParam.toString(); + } + } else { + // 如果前端传递的是字符串,直接使用 + sku = skuParam.toString().trim(); + } + }else{ + sku = null; + } // 5. 查询商品信息并验证 ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(goodId); if (serviceGoods == null) { @@ -3803,7 +3828,12 @@ public class AppletController extends BaseController { cartData.put("uid", cart.getUid()); cartData.put("good_id", cart.getGoodId()); cartData.put("good_num", cart.getGoodNum()); - cartData.put("sku", cart.getSku()); + if (cart.getSku() != null||cart.getSku() != "") { + cartData.put("sku", JSONObject.parseObject(cart.getSku())); + }else{ + cartData.put("sku", null); + } + // 格式化时间字段 cartData.put("created_at", cart.getCreatedAt() != null ? @@ -4399,10 +4429,11 @@ public class AppletController extends BaseController { + /** - * 创建服务订单 + * 创建服务订单(支持多商品批量下单) * - * @param params 请求参数,包含商品信息、地址信息和预约时间 + * @param params 请求参数,包含多个商品信息、地址信息和预约时间 * @param request HTTP请求对象 * @return 返回创建结果 */ @@ -4422,177 +4453,144 @@ public class AppletController extends BaseController { return error("用户信息获取失败"); } - // 3. 解析订单参数 - if (params == null || params.get("0") == null) { + // 3. 验证订单参数 + if (params == null || params.isEmpty()) { return error("订单参数不能为空"); } - Map orderParams = (Map) params.get("0"); - // 4. 验证必要参数 - Long productId = Long.valueOf(orderParams.get("product_id").toString()); - Long addressId = Long.valueOf(orderParams.get("address_id").toString()); + // 4. 生成主订单号 + String mainOrderId =GenerateCustomCode.generCreateOrder("WXB"); + // 5. 存储所有订单信息 + List> orderList = new ArrayList<>(); + BigDecimal totalAmount = BigDecimal.ZERO; // 总金额 - String sku = orderParams.get("sku") != null ? orderParams.get("sku").toString() : ""; - - // 5. 查询商品信息 - ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); - if (serviceGoods == null) { - return error("商品不存在"); - } - - // 6. 查询地址信息 - UserAddress userAddress = userAddressService.selectUserAddressById(addressId); - if (userAddress == null) { - return error("地址不存在"); - } - //判断如果是商品就添加商品订单,如果是服务就添加服务订单 - if(serviceGoods.getType()==2){ - Long num = Long.valueOf(orderParams.get("num").toString()); - - // 创建商品订单 - GoodsOrder goodsOrder = new GoodsOrder(); - goodsOrder.setType(2); - String mainOrderId = "WX" + System.currentTimeMillis(); - String orderId = "B" + System.currentTimeMillis(); - goodsOrder.setMainOrderId(mainOrderId); - goodsOrder.setOrderId(orderId); - goodsOrder.setUid(user.getId()); - goodsOrder.setProductId(productId); - goodsOrder.setName(userAddress.getName()); - goodsOrder.setPhone(userAddress.getPhone()); - goodsOrder.setAddress(userAddress.getAddressName()); - goodsOrder.setNum(num); - - // 计算订单金额 - BigDecimal totalPrice = serviceGoods.getPrice().multiply(BigDecimal.valueOf(num)); - goodsOrder.setTotalPrice(totalPrice); - goodsOrder.setGoodPrice(serviceGoods.getPrice()); - goodsOrder.setPayPrice(totalPrice); // 实际支付金额 - goodsOrder.setDeduction(new BigDecimal(0)); - goodsOrder.setStatus(1L); // 待支付状态 - goodsOrder.setAddressId(addressId); - goodsOrder.setSku(sku); - - // 保存订单到数据库 - int insertResult = goodsOrderService.insertGoodsOrder(goodsOrder); - if (insertResult <= 0) { - return error("订单创建失败,请稍后重试"); + // 6. 遍历所有订单项 + for (String key : params.keySet()) { + // 跳过非数字键 + if (!key.matches("\\d+")) { + continue; } - // 调用微信支付统一下单 - try { - // 准备支付参数 - String openid = user.getOpenid(); - if (openid == null || openid.trim().isEmpty()) { - return error("用户openid为空,无法发起支付"); + Map orderParams = (Map) params.get(key); + + // 验证必要参数 + if (orderParams.get("product_id") == null || orderParams.get("address_id") == null) { + return error("商品ID或地址ID不能为空"); + } + + Long productId = Long.valueOf(orderParams.get("product_id").toString()); + Long addressId = Long.valueOf(orderParams.get("address_id").toString()); + Long num = orderParams.get("num") != null ? Long.valueOf(orderParams.get("num").toString()) : 1L; + + // 处理SKU参数 + String sku = AppletControllerUtil.processSkuParam(orderParams.get("sku")); + + // 查询商品信息 + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); + if (serviceGoods == null) { + return error("商品ID " + productId + " 不存在"); + } + + // 查询地址信息(只需要查询一次,假设所有订单使用相同地址) + UserAddress userAddress = userAddressService.selectUserAddressById(addressId); + if (userAddress == null) { + return error("地址不存在"); + } + + // 计算单个订单金额 + BigDecimal itemPrice = serviceGoods.getPrice().multiply(BigDecimal.valueOf(num)); + totalAmount = totalAmount.add(itemPrice); + + // 判断商品类型并创建相应订单 + if (serviceGoods.getType() == 2) { + // 创建商品订单 + GoodsOrder goodsOrder = new GoodsOrder(); + goodsOrder.setType(2); + goodsOrder.setMainOrderId(mainOrderId); + goodsOrder.setOrderId(GenerateCustomCode.generCreateOrder("B")); // 独立订单号 + goodsOrder.setUid(user.getId()); + goodsOrder.setProductId(productId); + goodsOrder.setName(userAddress.getName()); + goodsOrder.setPhone(userAddress.getPhone()); + goodsOrder.setAddress(userAddress.getAddressName()); + goodsOrder.setNum(num); + goodsOrder.setTotalPrice(itemPrice); + goodsOrder.setGoodPrice(serviceGoods.getPrice()); + goodsOrder.setPayPrice(itemPrice); + goodsOrder.setDeduction(new BigDecimal(0)); + goodsOrder.setStatus(1L); // 待支付状态 + goodsOrder.setAddressId(addressId); + goodsOrder.setSku(sku); + + // 保存商品订单 + int insertResult = goodsOrderService.insertGoodsOrder(goodsOrder); + if (insertResult <= 0) { + return error("商品订单创建失败,请稍后重试"); } - // 金额转换为分(微信支付要求) - int totalFeeInCents = totalPrice.multiply(new BigDecimal(100)).intValue(); - String body = "商品订单-" + serviceGoods.getTitle(); - String notifyUrl = "https://4d983d7f.r3.cpolar.top/api/wechat/pay/notify"; // TODO: 预留回调地址,需要根据实际部署环境配置 - String attach = "goods_order:" + goodsOrder.getId(); // 附加数据,用于回调时识别订单类型 + // 添加到订单列表 + Map orderInfo = new HashMap<>(); + orderInfo.put("type", "goods"); + orderInfo.put("orderId", goodsOrder.getId()); + orderInfo.put("orderNo", goodsOrder.getOrderId()); + orderInfo.put("productName", serviceGoods.getTitle()); + orderInfo.put("price", itemPrice.toString()); + orderList.add(orderInfo); - // 调用微信支付工具类 - Map payResult = wechatPayUtil.unifiedOrder( - openid, - orderId, - totalFeeInCents, - body, - notifyUrl, - attach - ); + } else { + // 创建服务订单 + String makeTime = orderParams.get("make_time") != null ? orderParams.get("make_time").toString() : ""; - if (payResult != null && (Boolean) payResult.get("success")) { - // 支付下单成功,返回支付参数给前端 - Map payParams = (Map) payResult.get("payParams"); - Map responseData = new HashMap<>(); - responseData.put("orderId", goodsOrder.getId()); - responseData.put("orderNo", orderId); - responseData.put("totalPrice", totalPrice.toString()); - responseData.put("prepayId", payResult.get("prepayId")); + Order order = new Order(); + order.setType(1); // 1:服务项目 + order.setCreateType(1); // 1:用户自主下单 + order.setUid(user.getId()); + order.setUname(user.getName()); + order.setProductId(productId); + order.setProductName(serviceGoods.getTitle()); + order.setName(userAddress.getName()); + order.setPhone(userAddress.getPhone()); + order.setAddress(userAddress.getAddressInfo()); + order.setAddressId(addressId); + order.setSku(sku); + order.setMainOrderId(mainOrderId); + order.setOrderId(GenerateCustomCode.generCreateOrder("B")); // 独立订单号 - // 添加微信支付所需的参数(根据图片显示的格式) - if (payParams != null) { - responseData.put("appId", payParams.get("appId")); - responseData.put("timeStamp", payParams.get("timeStamp")); - responseData.put("nonceStr", payParams.get("nonceStr")); - responseData.put("package", payParams.get("package")); - responseData.put("signType", payParams.get("signType")); - responseData.put("paySign", payParams.get("paySign")); + // 处理预约时间 + if (makeTime != null && !makeTime.isEmpty()) { + String[] makeTimeArr = makeTime.split(" "); + if (makeTimeArr.length == 2) { + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Date date = sdf.parse(makeTimeArr[0]); + order.setMakeTime(date.getTime() / 1000); + order.setMakeHour(makeTimeArr[1]); + } catch (Exception e) { + logger.warn("预约时间格式错误: " + makeTime); + } } - - return AppletControllerUtil.appletSuccess(responseData); - } else { - // 支付下单失败,删除已创建的订单或标记为失败 - goodsOrder.setStatus(0L); // 标记为失败状态 - goodsOrderService.updateGoodsOrder(goodsOrder); - - String errorMsg = payResult != null ? (String) payResult.get("message") : "微信支付下单失败"; - return error("支付下单失败:" + errorMsg); } - } catch (Exception e) { - // 支付异常,删除已创建的订单或标记为失败 - goodsOrder.setStatus(0L); // 标记为失败状态 - goodsOrderService.updateGoodsOrder(goodsOrder); + order.setNum(num); + order.setTotalPrice(itemPrice); + order.setGoodPrice(serviceGoods.getPrice()); + order.setServicePrice(BigDecimal.ZERO); + order.setPayPrice(itemPrice); + order.setStatus(1L); // 1:待接单 + order.setReceiveType(1L); // 1:自由抢单 + order.setIsAccept(0); + order.setIsComment(0); + order.setIsPause(1); + order.setDeduction(new BigDecimal(0)); - logger.error("微信支付下单异常:", e); - return error("支付下单异常:" + e.getMessage()); - } + // 保存服务订单 + int result = orderService.insertOrder(order); + if (result <= 0) { + return error("服务订单创建失败,请稍后重试"); + } - }else{ - String makeTime = orderParams.get("make_time").toString(); - // 7. 创建订单对象 - Order order = new Order(); - order.setType(1); // 1:服务项目 - order.setCreateType(1); // 1:用户自主下单 - order.setUid(user.getId()); - order.setUname(user.getName()); - order.setProductId(productId); - order.setProductName(serviceGoods.getTitle()); - order.setName(userAddress.getName()); - order.setPhone(userAddress.getPhone()); - order.setAddress(userAddress.getAddressInfo()); - order.setAddressId(addressId); - order.setSku(sku); - - - // 解析预约时间 - String[] makeTimeArr = makeTime.split(" "); - if (makeTimeArr.length != 2) { - return error("预约时间格式错误"); - } - // 将日期字符串转换为时间戳 - try { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - Date date = sdf.parse(makeTimeArr[0]); - order.setMakeTime(date.getTime() / 1000); // 转换为秒级时间戳 - order.setMakeHour(makeTimeArr[1]); // 设置预约时间段 - } catch (Exception e) { - return error("预约时间格式错误"); - } - - order.setNum(1l); // 默认数量为1 - order.setTotalPrice(serviceGoods.getPrice()); // 总价等于商品价格 - order.setGoodPrice(serviceGoods.getPrice()); // 商品金额 - order.setServicePrice(BigDecimal.ZERO); // 服务金额默认为0 - order.setPayPrice(serviceGoods.getPrice()); // 支付金额等于总价 - order.setStatus(1L); // 1:待接单 - order.setReceiveType(1L); // 1:自由抢单 - order.setIsAccept(0); // 0:未接单 - order.setIsComment(0); // 0:未评价 - order.setIsPause(1); // 0:未暂停 - order.setDeduction(new BigDecimal(0)); - // 8. 生成订单号 - String orderId = generateOrderId(); - order.setOrderId(orderId); - order.setMainOrderId(orderId); - // 9. 保存订单 - int result = orderService.insertOrder(order); - if (result > 0) { - //10预约后添加到订单记录中 + // 添加订单日志 OrderLog orderLog = new OrderLog(); orderLog.setOid(order.getId()); orderLog.setOrderId(order.getOrderId()); @@ -4602,58 +4600,319 @@ public class AppletController extends BaseController { orderLog.setType(new BigDecimal(1.0)); orderLog.setContent(jsonObject.toString()); orderLogService.insertOrderLog(orderLog); - //完成订单的初步创建之后开始进行派单和发送订阅,以及预约师傅的操作 - //完成订单后的第一步,向用户发送订阅消息 - Order orderNewData= orderService.selectOrderById(order.getId()); - String wxsendmsg=WXsendMsgUtil.sendMsgForUserInfo(user.getOpenid(), orderNewData, serviceGoods); - //第二步系统派单 + + // 系统派单和消息通知逻辑 + Order orderNewData = orderService.selectOrderById(order.getId()); + String wxsendmsg = WXsendMsgUtil.sendMsgForUserInfo(user.getOpenid(), orderNewData, serviceGoods); Users worker = AppletControllerUtil.creatWorkerForOrder(orderNewData); - //第三步向师傅发送订阅消息 - if(worker!=null){ - //确定派单之后,更新订单状态为已派单,并添加订单日志记录 - //修改订单状态为派单开始------------------------------------------- + + if (worker != null) { + // 更新订单状态为已派单 orderNewData.setWorkerId(worker.getId()); orderNewData.setStatus(2l); orderNewData.setIsPause(1); orderNewData.setReceiveTime(new Date()); orderNewData.setReceiveType(3l); orderNewData.setLogStatus(9); - JSONObject jSONObject =new JSONObject(); - jSONObject.put("type",9); + JSONObject jSONObject = new JSONObject(); + jSONObject.put("type", 9); orderNewData.setLogJson(jSONObject.toJSONString()); orderService.updateOrder(orderNewData); + + // 添加派单日志 OrderLog orderLognew = new OrderLog(); orderLognew.setOid(orderNewData.getId()); orderLognew.setOrderId(orderNewData.getOrderId()); orderLognew.setTitle("平台派单"); orderLognew.setType(new BigDecimal(1.1)); - JSONObject jSONObject1 =new JSONObject(); - jSONObject1.put("name","师傅收到派单信息"); + JSONObject jSONObject1 = new JSONObject(); + jSONObject1.put("name", "师傅收到派单信息"); orderLognew.setContent(jSONObject1.toJSONString()); orderLognew.setWorkerId(worker.getId()); orderLognew.setWorkerLogId(worker.getId()); orderLogService.insertOrderLog(orderLognew); - //修改订单状态为派单结束------------------------------------------- - //给师傅发送微信订阅消息进行通知需要他进行接单 + + // 发送通知 WXsendMsgUtil.sendMsgForWorkerInfo(worker.getOpenid(), orderNewData, serviceGoods); - //第四步给师傅进行电话通知 YunXinPhoneUtilAPI.httpsAxbTransfer(worker.getPhone()); } - - System.out.println("wxsendmsg:" + wxsendmsg); - return success("预约成功"); - } else { - return error("预约失败,请稍后重试"); + // 添加到订单列表 + Map orderInfo = new HashMap<>(); + orderInfo.put("type", "service"); + orderInfo.put("orderId", order.getId()); + orderInfo.put("orderNo", order.getOrderId()); + orderInfo.put("productName", serviceGoods.getTitle()); + orderInfo.put("price", itemPrice.toString()); + orderList.add(orderInfo); } } + // 7. 如果有商品订单,需要发起微信支付 + boolean hasGoodsOrder = orderList.stream().anyMatch(order -> "goods".equals(order.get("type"))); + if (hasGoodsOrder && totalAmount.compareTo(BigDecimal.ZERO) > 0) { + // 使用工具类简化微信支付参数组装 + Map payResult = wechatPayUtil.createBatchOrderAndPay(user.getOpenid(), mainOrderId, new BigDecimal(0.01), orderList.size(),"https://4d983d7f.r3.cpolar.top/api/goods/pay/notify"); + //Map payResult = wechatPayUtil.createBatchOrderAndPay(user.getOpenid(), mainOrderId, totalAmount, orderList.size()); + if (payResult != null && Boolean.TRUE.equals(payResult.get("success"))) { + Map responseData = new HashMap<>(); + responseData.put("mainOrderId", mainOrderId); + responseData.put("orderList", orderList); + responseData.put("totalAmount", totalAmount.toString()); + responseData.put("prepayId", payResult.get("prepayId")); + // 直接合并所有支付参数 + responseData.putAll(payResult); + return AppletControllerUtil.appletSuccess(responseData); + } else { + String errorMsg = payResult != null ? (String) payResult.get("message") : "微信支付下单失败"; + return error("支付下单失败:" + errorMsg); + } + } else { + // 没有商品订单,只有服务订单,直接返回成功 + Map responseData = new HashMap<>(); + responseData.put("mainOrderId", mainOrderId); + responseData.put("orderList", orderList); + responseData.put("totalAmount", totalAmount.toString()); + return AppletControllerUtil.appletSuccess(responseData); + } } catch (Exception e) { - return error("预约失败:" + e.getMessage()); + logger.error("创建订单异常:", e); + return error("创建订单失败:" + e.getMessage()); } } + /** + * 尾款结算 + * + */ + @PostMapping("api/service/order/pay/total/price") + public AjaxResult apiServiceOrderPayTotalPprice(@RequestBody Map params, HttpServletRequest request) { + // 1. 验证用户登录状态 + String token = request.getHeader("token"); + Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); + if (!(Boolean) userValidation.get("valid")) { + return error("用户未登录或token无效"); + } + + // 2. 获取用户信息 + Users user = (Users) userValidation.get("user"); + if (user == null) { + return error("用户信息获取失败"); + } + + // 3. 验证必要参数 + if (params == null || params.get("id") == null ) { + return error("参数不能为空"); + } + Long worker_id = Long.valueOf(params.get("worker_id").toString()); + String order_id = params.get("order_id").toString(); + Order order = orderService.selectOrderByOrderId(order_id); + // 2. 查询订单日志(取type=5评估报价,或最新一条) + List logList = orderLogService.selectOrderLogByOrderId(order.getOrderId()); + OrderLog log = null; + for (OrderLog l : logList) { + if (l.getType() != null && l.getType().intValue() == 5) { + log = l; + break; + } + } + if (log == null && !logList.isEmpty()) { + log = logList.get(0); + } + if (log == null) { + return error("未找到订单日志"); + } + + Map payResult = wechatPayUtil.createBatchOrderAndPay( + user.getOpenid(), + String.valueOf(order_id), + new BigDecimal(0.01), + 1, + "https://4d983d7f.r3.cpolar.top/api/order/amount/pay/notify"); + if (payResult != null && Boolean.TRUE.equals(payResult.get("success"))) { + Map responseData = new HashMap<>(); + responseData.put("mainOrderId", order_id); + //responseData.put("orderList", orderList); + responseData.put("totalAmount",log.getPrice()); + responseData.put("prepayId", payResult.get("prepayId")); + // 直接合并所有支付参数 + responseData.putAll(payResult); + return AppletControllerUtil.appletSuccess(responseData); + } else { + String errorMsg = payResult != null ? (String) payResult.get("message") : "微信支付下单失败"; + return error("支付下单失败:" + errorMsg); + } + + + } + /** + * 上门费支付接口 + * + */ + + @PostMapping("api/service/order/pay_fee") + public AjaxResult apiServiceOrderPayFee(@RequestBody Map params, HttpServletRequest request) { + // 1. 验证用户登录状态 + String token = request.getHeader("token"); + Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); + if (!(Boolean) userValidation.get("valid")) { + return error("用户未登录或token无效"); + } + + // 2. 获取用户信息 + Users user = (Users) userValidation.get("user"); + if (user == null) { + return error("用户信息获取失败"); + } + + // 3. 验证必要参数 + if (params == null || params.get("id") == null ) { + return error("参数不能为空"); + } + Long orderId = Long.valueOf(params.get("id").toString()); + OrderLog orderLog = orderLogService.selectOrderLogById(orderId); + if (orderLog != null) { + + Map payResult = wechatPayUtil.createBatchOrderAndPay( + user.getOpenid(), + String.valueOf(orderLog.getId()), + new BigDecimal(0.01), + 1, + "https://4d983d7f.r3.cpolar.top/api/door/fee/pay/notify"); + if (payResult != null && Boolean.TRUE.equals(payResult.get("success"))) { + Map responseData = new HashMap<>(); + responseData.put("mainOrderId", String.valueOf(orderLog.getId())); + //responseData.put("orderList", orderList); + responseData.put("totalAmount",orderLog.getPrice()); + responseData.put("prepayId", payResult.get("prepayId")); + // 直接合并所有支付参数 + responseData.putAll(payResult); + return AppletControllerUtil.appletSuccess(responseData); + } else { + String errorMsg = payResult != null ? (String) payResult.get("message") : "微信支付下单失败"; + return error("支付下单失败:" + errorMsg); + } + + } + + + return error("支付失败"); + } + + + + + + /** + * 定金支付接口 + * + */ + + @PostMapping("/api/service/order/pay/deposit") + public AjaxResult apiServiceOrderPaydeposit(@RequestBody Map params, HttpServletRequest request) { + // 1. 验证用户登录状态 + String token = request.getHeader("token"); + Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); + if (!(Boolean) userValidation.get("valid")) { + return error("用户未登录或token无效"); + } + + // 2. 获取用户信息 + Users user = (Users) userValidation.get("user"); + if (user == null) { + return error("用户信息获取失败"); + } + + // 3. 验证必要参数 + if (params == null || params.get("id") == null ) { + return error("参数不能为空"); + } + Long orderId = Long.valueOf(params.get("id").toString()); + OrderLog orderLog = orderLogService.selectOrderLogById(orderId); + if (orderLog != null) { + + Map payResult = wechatPayUtil.createBatchOrderAndPay( + user.getOpenid(), + String.valueOf(orderLog.getId()), + new BigDecimal(0.01), + 1, + "https://4d983d7f.r3.cpolar.top/api/deposit/pay/notify"); + if (payResult != null && Boolean.TRUE.equals(payResult.get("success"))) { + Map responseData = new HashMap<>(); + responseData.put("mainOrderId", String.valueOf(orderLog.getId())); + //responseData.put("orderList", orderList); + responseData.put("totalAmount",orderLog.getPrice()); + responseData.put("prepayId", payResult.get("prepayId")); + // 直接合并所有支付参数 + responseData.putAll(payResult); + return AppletControllerUtil.appletSuccess(responseData); + } else { + String errorMsg = payResult != null ? (String) payResult.get("message") : "微信支付下单失败"; + return error("支付下单失败:" + errorMsg); + } + + } + + + return error("支付失败"); + } + + + /** + * 单个商品支付 + * + */ + @PostMapping("api/goods/order/once_pay") + public AjaxResult apiGoodsOrderOncePay(@RequestBody Map params, HttpServletRequest request) { + // 1. 验证用户登录状态 + String token = request.getHeader("token"); + Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); + if (!(Boolean) userValidation.get("valid")) { + return error("用户未登录或token无效"); + } + + // 2. 获取用户信息 + Users user = (Users) userValidation.get("user"); + if (user == null) { + return error("用户信息获取失败"); + } + + // 3. 验证必要参数 + if (params == null || params.get("id") == null ) { + return error("参数不能为空"); + } + Long orderId = Long.valueOf(params.get("id").toString()); + GoodsOrder goodsOrder= goodsOrderService.selectGoodsOrderById(orderId); + logger.info("orderId:{}",orderId); + logger.info("goodsOrder:{}",goodsOrder); + if (goodsOrder != null) { + goodsOrder.setMainOrderId(GenerateCustomCode.generCreateOrder("WXB")); + int flg=goodsOrderService.updateGoodsOrder(goodsOrder); + //修改成功就开始走支付功能 + if(flg>0){ + goodsOrder.setMainOrderId(goodsOrder.getMainOrderId()); + Map payResult = wechatPayUtil.createBatchOrderAndPay(user.getOpenid(), goodsOrder.getMainOrderId(), new BigDecimal(0.01), 1, "https://4d983d7f.r3.cpolar.top/api/goods/pay/notify"); + if (payResult != null && Boolean.TRUE.equals(payResult.get("success"))) { + Map responseData = new HashMap<>(); + responseData.put("mainOrderId", goodsOrder.getMainOrderId()); + //responseData.put("orderList", orderList); + responseData.put("totalAmount", goodsOrder.getTotalPrice()); + responseData.put("prepayId", payResult.get("prepayId")); + // 直接合并所有支付参数 + responseData.putAll(payResult); + return AppletControllerUtil.appletSuccess(responseData); + } else { + String errorMsg = payResult != null ? (String) payResult.get("message") : "微信支付下单失败"; + return error("支付下单失败:" + errorMsg); + } + + } + + + } + return error("支付失败"); + } /** * 生成订单号 @@ -4788,7 +5047,7 @@ public class AppletController extends BaseController { orderLog.setTitle("师傅接单"); orderLog.setType(new BigDecimal(2.0)); JSONObject js=new JSONObject(); - js.put("type", 1); + js.put("name", "同意系统配单"); orderLog.setContent(js.toJSONString()); orderLog.setWorkerId(order.getWorkerId()); orderLog.setWorkerLogId(order.getWorkerId()); @@ -5031,6 +5290,9 @@ public class AppletController extends BaseController { @GetMapping("/api/worker/order/info/{id}") public AjaxResult getWorkerOrderInfo(@PathVariable("id") Long id, HttpServletRequest request) { try { + // 4. 处理时间字段 + java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + // DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 1. 校验token并获取师傅信息 String token = request.getHeader("token"); Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); @@ -5104,8 +5366,8 @@ public class AppletController extends BaseController { logMap.put("coupon_id", log.getCouponId()); logMap.put("deduction", log.getDeduction()); logMap.put("worker_log_id", log.getWorkerLogId()); - logMap.put("created_at", log.getCreatedAt()); - logMap.put("updated_at", log.getUpdatedAt()); + logMap.put("created_at", log.getCreatedAt() != null ? dateFormat.format(log.getCreatedAt()) : null); + logMap.put("updated_at", log.getUpdatedAt() != null ? dateFormat.format(log.getUpdatedAt()) : null); logMap.put("deleted_at", log.getDeletedAt()); logArr.add(logMap); } @@ -5140,7 +5402,7 @@ public class AppletController extends BaseController { data.put("sku", order.getSku()); data.put("worker_id", order.getWorkerId()); data.put("first_worker_id", order.getFirstWorkerId()); - data.put("receive_time", order.getReceiveTime()); + data.put("receive_time",order.getReceiveTime() != null ? dateFormat.format(order.getReceiveTime()) : null); data.put("is_comment", order.getIsComment()); data.put("receive_type", order.getReceiveType()); data.put("is_accept", order.getIsAccept()); @@ -5154,9 +5416,9 @@ public class AppletController extends BaseController { data.put("log_json", order.getLogJson()); data.put("json_status", order.getJsonStatus()); data.put("log_images", order.getLogImages()); - data.put("created_at", order.getCreatedAt()); - data.put("updated_at", order.getUpdatedAt()); - data.put("deleted_at", order.getDeletedAt()); + data.put("created_at",order.getCreatedAt() != null ? dateFormat.format(order.getCreatedAt()) : null); + data.put("updated_at",order.getUpdatedAt() != null ? dateFormat.format(order.getUpdatedAt()) : null); + data.put("deleted_at",order.getDeletedAt() != null ? dateFormat.format(order.getDeletedAt()) : null); data.put("phone_xx", order.getPhone()); // 可脱敏处理 data.put("user", user); data.put("product", product); @@ -5167,6 +5429,89 @@ public class AppletController extends BaseController { } } + + + + + /** + * 支付尾款回调到页面的数据 + * 返回结构见json.txt + */ + @PostMapping("/api/service/order/pay/total/price/info") + public AjaxResult getOrderPayLastInfo(@RequestBody Map params) { + try { + String orderId = (String) params.get("order_id"); + if (StringUtils.isEmpty(orderId)) { + return error("订单号不能为空"); + } + + // 1. 查询订单 + Order order = orderService.selectOrderByOrderId(orderId); + if (order == null) { + return error("订单不存在"); + } + + // 2. 查询订单日志(取type=5评估报价,或最新一条) + List logList = orderLogService.selectOrderLogByOrderId(orderId); + OrderLog log = null; + for (OrderLog l : logList) { + if (l.getType() != null && l.getType().intValue() == 5) { + log = l; + break; + } + } + if (log == null && !logList.isEmpty()) { + log = logList.get(0); + } + if (log == null) { + return error("未找到订单日志"); + } + + // 3. 组装content字段 + JSONObject contentJson; + try { + contentJson = JSONObject.parseObject(log.getContent()); + } catch (Exception e) { + contentJson = new JSONObject(); + } + + // 4. 组装返回数据 + Map data = new HashMap<>(); + data.put("id", log.getId()); + data.put("oid", log.getOid()); + data.put("order_id", log.getOrderId()); + data.put("log_order_id", log.getLogOrderId()); + data.put("title", log.getTitle()); + data.put("type", log.getType() != null ? log.getType().intValue() : null); + data.put("content", contentJson); + data.put("deposit", log.getDeposit() != null ? log.getDeposit().toString() : "0.00"); + data.put("dep_paid", log.getDepPaid()); + data.put("dep_pay_time", log.getDepPayTime()); + data.put("dep_log_id", log.getDepLogId()); + data.put("price", log.getPrice() != null ? log.getPrice().toString() : "0.00"); + data.put("paid", log.getPaid()); + data.put("pay_time", log.getPayTime() != null ? new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(log.getPayTime() * 1000)) : null); + data.put("log_id", log.getLogId()); + data.put("worker_id", log.getWorkerId()); + data.put("first_worker_id", log.getFirstWorkerId()); + data.put("give_up", log.getGiveUp()); + data.put("worker_cost", log.getWorkerCost()); + data.put("reduction_price", log.getReductionPrice() != null ? log.getReductionPrice().toString() : "0.00"); + data.put("is_pause", log.getIsPause()); + data.put("coupon_id", log.getCouponId()); + data.put("deduction", log.getDeduction()); + data.put("worker_log_id", log.getWorkerLogId()); + data.put("created_at", log.getCreatedAt() != null ? new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(log.getCreatedAt()) : null); + data.put("updated_at", log.getUpdatedAt() != null ? new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(log.getUpdatedAt()) : null); + data.put("deleted_at", log.getDeletedAt()); + + return success(data); + } catch (Exception e) { + return error("查询失败:" + e.getMessage()); + } + } + + /** * 师傅列表接口 * 返回结构见json.txt @@ -5903,6 +6248,8 @@ public class AppletController extends BaseController { } // 查询最新订单日志 OrderLog neworderLog = orderLogService.selectDataTheFirstNew(order.getId()); + System.out.println("######################"+order.getId()); + System.out.println("^^^^^^^^^^^^^^^^^^^^^^"+neworderLog.getId()); if (neworderLog!=null){ //修改订单日志添加费用 neworderLog.setPrice(price); @@ -5914,11 +6261,13 @@ public class AppletController extends BaseController { JSONObject jsonObject3 = new JSONObject(); jsonObject3.put("type", 2); order.setLogJson(jsonObject3.toJSONString()); + orderLogService.updateOrderLog(neworderLog); orderService.updateOrder(order); Users userinfo = usersService.selectUsersById(order.getUid()); ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId()); //给用户发送微信推送消息 - WXsendMsgUtil.sendMsgForUserDoorMoney(userinfo.getOpenid(),order,serviceGoods); } + WXsendMsgUtil.sendMsgForUserDoorMoney(userinfo.getOpenid(),order,serviceGoods); + } // List logList = orderLogService.selectOrderLogByOrderId(order.getOrderId()); // if (logList == null || logList.isEmpty()) { // return AppletControllerUtil.appletWarning("订单日志不存在"); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/CoursorUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/CoursorUtil.java index 6b0155d..c31baab 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/CoursorUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/CoursorUtil.java @@ -3,7 +3,6 @@ package com.ruoyi.system.controller; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.system.ControllerUtil.AppletControllerUtil; -import com.ruoyi.system.ControllerUtil.WechatPayUtil; import com.ruoyi.system.domain.ServiceGoods; import com.ruoyi.system.domain.GoodsOrderCursor; import com.ruoyi.system.service.IServiceGoodsService; @@ -12,9 +11,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; +import java.math.BigDecimal; import java.util.*; /** @@ -33,9 +34,6 @@ public class CoursorUtil extends BaseController { @Autowired private IGoodsOrderCursorService goodsOrderCursorService; - @Autowired - private WechatPayUtil wechatPayUtil; - /** * 获取服务商品详细信息 * @@ -45,8 +43,8 @@ public class CoursorUtil extends BaseController { *

* 接口说明: * - 根据商品ID获取详细信息 - * - type=1时返回ServiceGoodsResponse格式 - * - type=2时返回json.txt中的商品格式 + * - type=1时返回服务商品格式 + * - type=2时返回普通商品格式 * - 包含图片、基础信息等数组数据 */ @GetMapping(value = "/api/service/infoData/id/{id}") @@ -63,143 +61,170 @@ public class CoursorUtil extends BaseController { return AppletControllerUtil.appletError("商品不存在或已下架"); } - // 根据商品类型返回不同格式的数据 - if (serviceGoodsData.getType() != null && serviceGoodsData.getType().intValue() == 2) { - // type=2时返回json.txt格式 - Map goodsData = AppletControllerUtil.buildType2ServiceGoodsResponse(serviceGoodsData); + // 构建返回数据 + Map goodsData = buildServiceGoodsResponse(serviceGoodsData); return AppletControllerUtil.appletSuccess(goodsData); - } else { - // type=1时返回ServiceGoodsResponse格式 - AppletControllerUtil.ServiceGoodsResponse response = new AppletControllerUtil.ServiceGoodsResponse(serviceGoodsData); - return AppletControllerUtil.appletSuccess(response); - } + } catch (Exception e) { return AppletControllerUtil.appletError("查询商品详情失败:" + e.getMessage()); } } /** - * 微信支付回调通知接口 + * 获取订单游标信息 * + * @param id 游标ID * @param request HTTP请求对象 - * @return XML格式的响应给微信服务器 - *

- * 接口说明: - * - 接收微信支付成功后的异步通知 - * - 验证签名确保数据安全性 - * - 处理支付成功后的业务逻辑 - * - 返回XML格式响应告知微信处理结果 - *

- * 微信支付回调特点: - * - 微信会POST XML数据到此接口 - * - 必须返回XML格式的成功/失败响应 - * - 如果返回失败,微信会重复发送通知 - * - 建议做幂等性处理,避免重复处理同一笔订单 + * @return 游标详细信息 */ - @PostMapping(value = "/api/wechatdata/pay/notify") - public String handleWechatPayNotify(HttpServletRequest request) { + @GetMapping(value = "/api/cursor/order/info/{id}") + public AjaxResult getOrderCursorInfo(@PathVariable("id") long id, HttpServletRequest request) { try { - // 记录回调日志(可选) - logger.info("收到微信支付回调通知,开始处理..."); - - // 1. 使用WechatPayUtil处理支付回调 - Map notifyResult = wechatPayUtil.handlePayNotify(request); - - // 2. 检查处理结果 - boolean success = (Boolean) notifyResult.get("success"); - String message = (String) notifyResult.get("message"); - - if (success) { - // 3. 获取支付信息 - Map paymentInfo = (Map) notifyResult.get("paymentInfo"); - - // 4. 处理支付成功的业务逻辑 - handlePaymentSuccessLogic(paymentInfo); - - // 5. 记录成功日志 - logger.info("微信支付回调处理成功:订单号={}, 微信交易号={}", - paymentInfo.get("outTradeNo"), paymentInfo.get("transactionId")); - - // 6. 返回成功响应给微信 - return buildSuccessResponse(); - - } else { - // 7. 处理失败情况 - logger.error("微信支付回调处理失败:{}", message); - - // 8. 返回失败响应给微信 - return buildFailResponse(message); + // 参数验证 + if (id <= 0) { + return AppletControllerUtil.appletError("游标ID无效"); } - - } catch (Exception e) { - // 9. 异常处理 - logger.error("微信支付回调处理异常:", e); - - // 10. 返回异常响应给微信 - return buildFailResponse("处理异常:" + e.getMessage()); - } - } - - /** - * 处理支付成功后的业务逻辑 - * - * @param paymentInfo 支付信息 - */ - private void handlePaymentSuccessLogic(Map paymentInfo) { - try { - String outTradeNo = (String) paymentInfo.get("outTradeNo"); - String transactionId = (String) paymentInfo.get("transactionId"); - String totalFee = (String) paymentInfo.get("totalFee"); - String timeEnd = (String) paymentInfo.get("timeEnd"); - String attach = (String) paymentInfo.get("attach"); - String openid = (String) paymentInfo.get("openid"); - - logger.info("开始处理支付成功业务逻辑:订单号={}, 金额={}", outTradeNo, totalFee); - - // TODO: 根据实际业务需求实现以下逻辑 - // 1. 更新订单状态为已支付 - // 2. 记录支付流水 - // 3. 发送支付成功通知给用户 - // 4. 触发后续业务流程(如发货、服务安排等) - // 5. 更新库存(如果是商品订单) - - // 示例:如果是商品订单临时表的支付 - if (attach != null && attach.startsWith("cursor_order:")) { - String cursorOrderId = attach.replace("cursor_order:", ""); - // 可以在这里处理商品订单临时表的状态更新 - logger.info("处理商品订单临时表支付:ID={}", cursorOrderId); - } - - // 调用AppletControllerUtil的通用支付成功处理方法 - AppletControllerUtil.handlePaymentSuccess(paymentInfo, false); - - logger.info("支付成功业务逻辑处理完成:订单号={}", outTradeNo); - - } catch (Exception e) { - logger.error("处理支付成功业务逻辑异常:", e); - // 注意:即使业务逻辑处理失败,也应该向微信返回成功响应 - // 避免微信重复发送通知,可以通过日志或其他方式处理业务异常 - } - } - - /** - * 构建成功响应XML - */ - private String buildSuccessResponse() { - return "" + - "" + - "" + - ""; - } - - /** - * 构建失败响应XML - */ - private String buildFailResponse(String message) { - return "" + - "" + - "" + - ""; - } -} + // 查询游标信息 + GoodsOrderCursor cursor = goodsOrderCursorService.selectGoodsOrderCursorById(id); + if (cursor == null) { + return AppletControllerUtil.appletError("游标信息不存在"); + } + + // 构建返回数据 + Map cursorData = buildCursorResponse(cursor); + return AppletControllerUtil.appletSuccess(cursorData); + + } catch (Exception e) { + return AppletControllerUtil.appletError("查询游标信息失败:" + e.getMessage()); + } + } + + /** + * 创建订单游标 + * + * @param params 游标参数 + * @param request HTTP请求对象 + * @return 创建结果 + */ + @PostMapping(value = "/api/cursor/order/create") + public AjaxResult createOrderCursor(@RequestBody Map params, HttpServletRequest request) { + try { + // 参数验证 + if (params == null || params.isEmpty()) { + return AppletControllerUtil.appletError("参数不能为空"); + } + + // 创建游标对象 + GoodsOrderCursor cursor = new GoodsOrderCursor(); + + // 设置基本信息 + if (params.get("productId") != null) { + cursor.setProductId(Long.valueOf(params.get("productId").toString())); + } + + if (params.get("sku") != null) { + cursor.setSku(params.get("sku").toString()); + } + + if (params.get("type") != null) { + cursor.setType(Long.valueOf(params.get("type").toString())); + } + + if (params.get("num") != null) { + cursor.setNum(Long.valueOf(params.get("num").toString())); + } + + if (params.get("totalPrice") != null) { + cursor.setTotalPrice(new BigDecimal(params.get("totalPrice").toString())); + } + + // 保存游标 + int result = goodsOrderCursorService.insertGoodsOrderCursor(cursor); + if (result > 0) { + Map responseData = new HashMap<>(); + responseData.put("cursorId", cursor.getId()); + return AppletControllerUtil.appletSuccess(responseData); + } else { + return AppletControllerUtil.appletError("创建游标失败"); + } + + } catch (Exception e) { + return AppletControllerUtil.appletError("创建游标失败:" + e.getMessage()); + } + } + + /** + * 构建服务商品响应数据 + * + * @param serviceGoods 服务商品对象 + * @return 响应数据 + */ + private Map buildServiceGoodsResponse(ServiceGoods serviceGoods) { + Map goodsData = new HashMap<>(); + + // 基础信息 + goodsData.put("id", serviceGoods.getId()); + goodsData.put("title", serviceGoods.getTitle()); + goodsData.put("sub_title", serviceGoods.getSubTitle()); + goodsData.put("price", serviceGoods.getPrice()); + goodsData.put("type", serviceGoods.getType()); + goodsData.put("status", serviceGoods.getStatus()); + + // 图片信息 + goodsData.put("icon", AppletControllerUtil.buildImageUrl(serviceGoods.getIcon())); + + // 详细信息 + if (serviceGoods.getDescription() != null) { + goodsData.put("description", serviceGoods.getDescription()); + } + + // 简介信息 + if (serviceGoods.getInfo() != null) { + goodsData.put("info", serviceGoods.getInfo()); + } + + // 分类信息 + if (serviceGoods.getCateId() != null) { + goodsData.put("cate_id", serviceGoods.getCateId()); + } + + // 根据商品类型添加特定字段 + if (serviceGoods.getType() != null && serviceGoods.getType().intValue() == 2) { + // 普通商品特有字段 + goodsData.put("stock", serviceGoods.getStock() != null ? serviceGoods.getStock() : 0); + goodsData.put("sales", serviceGoods.getSales() != null ? serviceGoods.getSales() : 0); + goodsData.put("postage", serviceGoods.getPostage() != null ? serviceGoods.getPostage() : BigDecimal.ZERO); + } else { + // 服务商品特有字段 + goodsData.put("service_type", "service"); + goodsData.put("project", serviceGoods.getProject() != null ? serviceGoods.getProject() : ""); + goodsData.put("basic", serviceGoods.getBasic() != null ? serviceGoods.getBasic() : ""); + goodsData.put("material", serviceGoods.getMaterial() != null ? serviceGoods.getMaterial() : ""); + } + + return goodsData; + } + + /** + * 构建游标响应数据 + * + * @param cursor 游标对象 + * @return 响应数据 + */ + private Map buildCursorResponse(GoodsOrderCursor cursor) { + Map cursorData = new HashMap<>(); + + cursorData.put("id", cursor.getId()); + cursorData.put("productId", cursor.getProductId()); + cursorData.put("sku", cursor.getSku()); + cursorData.put("type", cursor.getType()); + cursorData.put("num", cursor.getNum()); + cursorData.put("totalPrice", cursor.getTotalPrice()); + cursorData.put("postage", cursor.getPostage()); + cursorData.put("createdAt", cursor.getCreatedAt()); + cursorData.put("updatedAt", cursor.getUpdatedAt()); + + return cursorData; + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/PayNotifyController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/PayNotifyController.java new file mode 100644 index 0000000..144600a --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/PayNotifyController.java @@ -0,0 +1,949 @@ +package com.ruoyi.system.controller; + +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.system.ControllerUtil.GenerateCustomCode; +import com.ruoyi.system.ControllerUtil.WXsendMsgUtil; +import com.ruoyi.system.ControllerUtil.WechatPayUtil; +import com.ruoyi.system.domain.*; +import com.ruoyi.system.service.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.math.BigDecimal; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 支付回调控制器 + * + * 处理各种支付场景的微信支付回调通知 + * 所有回调接口都以api开头,符合项目规范 + * + * @author Mr. Zhang Pan + * @date 2025-06-16 + * @version 1.0 + */ +@RestController +public class PayNotifyController extends BaseController { + + private static final Logger logger = LoggerFactory.getLogger(PayNotifyController.class); + + @Autowired + private WechatPayUtil wechatPayUtil; + + @Autowired + private IGoodsOrderService goodsOrderService; + + @Autowired + private IOrderService orderService; + + @Autowired + private IOrderLogService orderLogService; + + @Autowired + private IUsersService usersService; + + @Autowired + private IServiceGoodsService serviceGoodsService; + + @Autowired + private ISiteConfigService siteConfigService; + + @Autowired + private IIntegralLogService integralLogService; + + @Autowired + private IPayMoneyLogService payMoneyLogService; + + + @Autowired + private IWorkerLevelService workerLevelService; + + @Autowired + private IWorkerMarginLogService workerMarginLogService; + + /** + * 商品支付回调接口 + * + * @param request HTTP请求对象 + * @return XML格式响应给微信服务器 + * + * 处理商品订单的支付成功回调: + * 1. 验证支付签名 + * 2. 更新商品订单支付状态 + * 3. 更新订单支付时间和交易号 + * 4. 处理库存扣减等业务逻辑 + */ + @PostMapping(value = "/api/goods/pay/notify") + public String apiGoodsPayNotify(HttpServletRequest request) { + try { + logger.info("收到商品支付回调通知,开始处理..."); + + // 1. 使用WechatPayUtil处理支付回调 + Map notifyResult = wechatPayUtil.handlePayNotify(request); + + // 2. 检查处理结果 + boolean success = (Boolean) notifyResult.get("success"); + String message = (String) notifyResult.get("message"); + + if (!success) { + logger.error("商品支付回调处理失败:{}", message); + return buildFailResponse("商品支付回调处理失败"); + } + + // 3. 获取支付信息 + Map paymentInfo = (Map) notifyResult.get("paymentInfo"); + String outTradeNo = (String) paymentInfo.get("outTradeNo"); + String transactionId = (String) paymentInfo.get("transactionId"); + String totalFee = (String) paymentInfo.get("totalFee"); + + // 4. 查询对应的商品订单 + GoodsOrder goodsOrder = new GoodsOrder(); + goodsOrder.setMainOrderId(outTradeNo); + List goodsOrderslist = goodsOrderService.selectGoodsOrderList(goodsOrder); + +// if (!goodsOrderslist.isEmpty()) { +// logger.error("商品订单不存在,订单号:{}", outTradeNo); +// return buildFailResponse("商品订单不存在"); +// } + +// // 5. 检查订单状态,避免重复处理 +// if (goodsOrder.getStatus() != null && goodsOrder.getStatus() == 2L) { +// logger.info("商品订单已支付,订单号:{}", outTradeNo); +// return buildSuccessResponse(); +// } + long uid = Long.parseLong("0"); + // 6. 更新商品订单状态 + for (GoodsOrder goodsOrderData : goodsOrderslist){ + uid= goodsOrderData.getUid(); + goodsOrderData.setStatus(2L); // 2:已支付 + goodsOrderData.setPayTime(new Date()); + goodsOrderData.setTransactionId(transactionId); + int updateResult = goodsOrderService.updateGoodsOrder(goodsOrderData); + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(goodsOrderData.getProductId()); + Users userinfo = usersService.selectUsersById(goodsOrderData.getUid()); + WXsendMsgUtil.sendUserForMoneySuccess(userinfo.getOpenid(),goodsOrder,serviceGoods); + } +// if (updateResult <= 0) { +// logger.error("更新商品订单状态失败,订单号:{}", outTradeNo); +// return buildFailResponse("更新订单状态失败"); +// } + Users users =usersService.selectUsersById(uid); + + // 7. 处理商品订单支付成功后的业务逻辑 + handleGoodsPaymentSuccess(users,outTradeNo, paymentInfo); + //8向客户推送微信消息 + + //sendWechatMessage(users,outTradeNo); + logger.info("商品支付回调处理成功,订单号:{}", outTradeNo); + return buildSuccessResponse(); + + } catch (Exception e) { + logger.error("商品支付回调处理异常:", e); + return buildFailResponse("商品支付回调处理异常"); + } + } + + /** + * 上门费支付回调接口 + * + * @param request HTTP请求对象 + * @return XML格式响应给微信服务器 + * + * 处理上门费的支付成功回调: + * 1. 验证支付签名 + * 2. 更新订单日志中的上门费支付状态 + * 3. 更新订单状态为已支付上门费 + * 4. 通知师傅可以开始上门服务 + */ + @PostMapping(value = "/api/door/fee/pay/notify") + public String apiDoorFeePayNotify(HttpServletRequest request) { + try { + logger.info("收到上门费支付回调通知,开始处理..."); + + // 1. 使用WechatPayUtil处理支付回调 + Map notifyResult = wechatPayUtil.handlePayNotify(request); + + // 2. 检查处理结果 + boolean success = (Boolean) notifyResult.get("success"); + String message = (String) notifyResult.get("message"); + + if (!success) { + logger.error("上门费支付回调处理失败:{}", message); + return buildFailResponse("上门费支付回调处理失败"); + } + + // 3. 获取支付信息 + Map paymentInfo = (Map) notifyResult.get("paymentInfo"); + String outTradeNo = (String) paymentInfo.get("outTradeNo"); + String transactionId = (String) paymentInfo.get("transactionId"); + String totalFee = (String) paymentInfo.get("totalFee"); + + // 4. 查询对应的订单日志(上门费记录) + OrderLog orderLog = orderLogService.selectOrderLogById(Long.parseLong(outTradeNo)); + if (orderLog == null) { + logger.error("上门费订单记录不存在,订单号:{}", outTradeNo); + return buildFailResponse("上门费订单记录不存在"); + } + + // 5. 检查支付状态,避免重复处理 + if (orderLog.getPaid() != null && orderLog.getPaid() == 2L) { + logger.info("上门费已支付,订单号:{}", outTradeNo); + return buildSuccessResponse(); + } + + // 6. 更新上门费支付状态 + orderLog.setPaid(2L); // 1:已支付 + orderLog.setWorkerCost(new BigDecimal(totalFee)); + orderLog.setPayTime(System.currentTimeMillis()/1000); + //orderLog.setUpdateTime(new Date()); + + int updateResult = orderLogService.updateOrderLog(orderLog); + logger.error("更新上门费支付状态失败,订单号:{}", outTradeNo); + if (updateResult <= 0) { + logger.error("更新上门费支付状态失败,订单号:{}", outTradeNo); + return buildFailResponse("更新上门费支付状态失败"); + } + +// // 7. 更新主订单状态 + Order mainOrder = orderService.selectOrderByOrderId(orderLog.getOrderId()); + Users users = usersService.selectUsersById(mainOrder.getUid()); +// if (mainOrder != null) { +// // 更新订单状态,表示上门费已支付 +// JSONObject logJson = new JSONObject(); +// logJson.put("type", 3); +// logJson.put("doorFeePaid", true); +// mainOrder.setLogJson(logJson.toJSONString()); +// mainOrder.setJsonStatus(4); // 4:已支付上门费,可以出发上门 +// orderService.updateOrder(mainOrder); +// } + + // 8. 处理上门费支付成功后的业务逻辑 + handleDoorFeePaymentSuccess(orderLog, paymentInfo); + + // 2. 处理积分奖励 + handleIntegralReward(users, paymentInfo, "付款赠送积分"); + //微信推送给师傅用户已支付上门费String openid, Order order, ServiceGoods serviceGoods + Users worker=usersService.selectUsersById(mainOrder.getWorkerId()); + if (worker != null){ + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(mainOrder.getProductId()); + if (serviceGoods != null){ + WXsendMsgUtil.sendUserPayDoorMoneyForWorker(worker.getOpenid(),mainOrder,serviceGoods); + } + + } + + logger.info("上门费支付回调处理成功,订单号:{}", outTradeNo); + return buildSuccessResponse(); + + } catch (Exception e) { + logger.error("上门费支付回调处理异常:", e); + return buildFailResponse("上门费支付回调处理异常"); + } + } + + /** + * 定金支付回调接口 + * + * @param request HTTP请求对象 + * @return XML格式响应给微信服务器 + * + * 处理定金的支付成功回调: + * 1. 验证支付签名 + * 2. 更新订单日志中的定金支付状态 + * 3. 更新订单状态为已支付定金 + * 4. 记录定金支付时间和交易号 + */ + @PostMapping(value = "/api/deposit/pay/notify") + public String apiDepositPayNotify(HttpServletRequest request) { + try { + logger.info("收到定金支付回调通知,开始处理..."); + + // 1. 使用WechatPayUtil处理支付回调 + Map notifyResult = wechatPayUtil.handlePayNotify(request); + + // 2. 检查处理结果 + boolean success = (Boolean) notifyResult.get("success"); + String message = (String) notifyResult.get("message"); + + if (!success) { + logger.error("定金支付回调处理失败:{}", message); + return buildFailResponse("定金支付回调处理失败"); + } + + // 3. 获取支付信息 + Map paymentInfo = (Map) notifyResult.get("paymentInfo"); + String outTradeNo = (String) paymentInfo.get("outTradeNo"); + String transactionId = (String) paymentInfo.get("transactionId"); + String totalFee = (String) paymentInfo.get("totalFee"); + + // 4. 查询对应的订单日志(定金记录) + OrderLog orderLog = orderLogService.selectOrderLogById(Long.parseLong(outTradeNo)); + if (orderLog == null) { + logger.error("定金订单记录不存在,订单号:{}", outTradeNo); + return buildFailResponse("定金订单记录不存在"); + } + + // 5. 检查定金支付状态,避免重复处理 + if (orderLog.getDepPaid() != null && orderLog.getDepPaid() == 2) { + logger.info("定金已支付,订单号:{}", outTradeNo); + return buildSuccessResponse(); + } + + // 6. 更新定金支付状态 + orderLog.setDepPaid(2); // 1:已支付 + orderLog.setDepPayTime(System.currentTimeMillis()/1000); + // orderLog.setUpdateTime(new Date()); + + int updateResult = orderLogService.updateOrderLog(orderLog); + if (updateResult <= 0) { + logger.error("更新定金支付状态失败,订单号:{}", outTradeNo); + return buildFailResponse("更新定金支付状态失败"); + } + +// // 7. 更新主订单状态 + Order mainOrder = orderService.selectOrderByOrderId(orderLog.getOrderId()); +// if (mainOrder != null) { +// // 更新订单状态,表示定金已支付 +// JSONObject logJson = new JSONObject(); +// logJson.put("type", 4); +// logJson.put("depositPaid", true); +// mainOrder.setLogJson(logJson.toJSONString()); +// orderService.updateOrder(mainOrder); +// } + + // 8. 处理定金支付成功后的业务逻辑 + Users users = usersService.selectUsersById(mainOrder.getUid()); + handleDepositPaymentSuccess(users,orderLog, paymentInfo); + + logger.info("定金支付回调处理成功,订单号:{}", outTradeNo); + return buildSuccessResponse(); + + } catch (Exception e) { + logger.error("定金支付回调处理异常:", e); + return buildFailResponse("定金支付回调处理异常"); + } + } + + /** + * 订单金额支付回调接口 + * + * @param request HTTP请求对象 + * @return XML格式响应给微信服务器 + * + * 处理订单总金额的支付成功回调: + * 1. 验证支付签名 + * 2. 更新服务订单支付状态 + * 3. 更新订单支付时间和交易号 + * 4. 处理订单支付完成后的业务逻辑 + */ + @PostMapping(value = "/api/order/amount/pay/notify") + public String apiOrderAmountPayNotify(HttpServletRequest request) { + try { + logger.info("收到订单金额支付回调通知,开始处理..."); + + // 1. 使用WechatPayUtil处理支付回调 + Map notifyResult = wechatPayUtil.handlePayNotify(request); + + // 2. 检查处理结果 + boolean success = (Boolean) notifyResult.get("success"); + String message = (String) notifyResult.get("message"); + + if (!success) { + logger.error("订单金额支付回调处理失败:{}", message); + return buildFailResponse("订单金额支付回调处理失败"); + } + + // 3. 获取支付信息 + Map paymentInfo = (Map) notifyResult.get("paymentInfo"); + String outTradeNo = (String) paymentInfo.get("outTradeNo"); + String transactionId = (String) paymentInfo.get("transactionId"); + String totalFee = (String) paymentInfo.get("totalFee"); + + // 4. 查询对应的服务订单 + Order order = orderService.selectOrderByOrderId(outTradeNo); + + if (order == null) { + logger.error("服务订单不存在,订单号:{}", outTradeNo); + return buildFailResponse("服务订单不存在"); + } + + // 5. 检查订单支付状态,避免重复处理 + if (order.getStatus() != null && order.getStatus() == 2L) { + logger.info("订单已支付,订单号:{}", outTradeNo); + return buildSuccessResponse(); + } + //更新最新的一条日志信息 + OrderLog orderLog = orderLogService.selectDataTheFirstNew(order.getId()); + orderLog.setPayTime(System.currentTimeMillis()/1000); + orderLog.setPaid(2L); + orderLogService.updateOrderLog(orderLog); + + // 6. 更新订单支付状态 + order.setStatus(4L); // 2:已支付 + order.setTransactionId(transactionId); + order.setPayTime(new Date()); + //order.setUpdateTime(new Date()); + + // 计算实际支付金额(分转换为元) + BigDecimal paidAmount = new BigDecimal(totalFee).divide(new BigDecimal(100)); + order.setPayPrice(paidAmount); + + int updateResult = orderService.updateOrder(order); + if (updateResult <= 0) { + logger.error("更新订单支付状态失败,订单号:{}", outTradeNo); + return buildFailResponse("更新订单支付状态失败"); + } + + // 7. 处理订单支付成功后的业务逻辑 + handleOrderAmountPaymentSuccess(order, paymentInfo); + calculateCommissionMoney(order.getOrderId(), order.getUid(),order.getWorkerId()); + logger.info("订单金额支付回调处理成功,订单号:{}", outTradeNo); + return buildSuccessResponse(); + + } catch (Exception e) { + logger.error("订单金额支付回调处理异常:", e); + return buildFailResponse("订单金额支付回调处理异常"); + } + } + + /** + * 处理商品支付成功后的业务逻辑 + */ + private void handleGoodsPaymentSuccess(Users users,String outTradeNo, Map paymentInfo) { + try { + // 1. 记录支付成功日志 + logger.info("商品订单支付成功,订单号:{},支付金额:{}", + outTradeNo, paymentInfo.get("totalFee")); + + // 2. 处理积分奖励 + handleIntegralReward(users, paymentInfo, "下单赠送积分"); + + // 3. 记录支付记录 + recordPaymentLog(outTradeNo, paymentInfo,"支付订单金额"); + + } catch (Exception e) { + logger.error("处理商品支付成功业务逻辑异常:", e); + } + } + + /** + * 处理上门费支付成功后的业务逻辑 + */ + private void handleDoorFeePaymentSuccess(OrderLog orderLog, Map paymentInfo) { + try { + // 1. 记录支付成功日志 + logger.info("上门费支付成功,订单号:{},支付金额:{}", + orderLog.getLogOrderId(), paymentInfo.get("totalFee")); + + // 2. 获取主订单信息以获取用户信息 + Order mainOrder = orderService.selectOrderByOrderId(orderLog.getOrderId()); + if (mainOrder != null) { + // 3. 上门费支付不赠送积分(按照PHP逻辑) + logger.info("上门费支付不赠送积分"); + + recordPaymentLogones(orderLog.getOid(), orderLog.getLogOrderId(),mainOrder.getUid(),mainOrder.getUname(), paymentInfo, "支付上门费"); + + +//// // 4. 记录支付记录 +// recordPaymentLog(orderLog.getOid(), orderLog.getLogOrderId(), +// mainOrder.getUid(), mainOrder.getUname(), paymentInfo, "支付" + mainOrder.getProductName() + "上门费"); + } + + } catch (Exception e) { + logger.error("处理上门费支付成功业务逻辑异常:", e); + } + } + + /** + * 处理定金支付成功后的业务逻辑 + */ + private void handleDepositPaymentSuccess(Users users,OrderLog orderLog, Map paymentInfo) { + try { + // 1. 记录支付成功日志 + logger.info("定金支付成功,订单号:{},支付金额:{}", + orderLog.getDepLogId(), paymentInfo.get("totalFee")); + + // 2. 获取主订单信息以获取用户信息 + Order mainOrder = orderService.selectOrderByOrderId(orderLog.getOrderId()); + if (mainOrder != null) { + + + + // 2. 处理积分奖励 + handleIntegralReward(users, paymentInfo, "支付赠送积分"); + // long oid,String orderid,long uid,String uname,Map paymentInfo, String description + // 3. 记录支付记录 + recordPaymentLogones(orderLog.getOid(), orderLog.getOrderId(),users.getId(),users.getName(), paymentInfo,"支付定金金额"); + +// // 3. 处理积分奖励 +// handleIntegralReward(orderLog.getDepLogId(), mainOrder.getUid(), +// mainOrder.getUname(), paymentInfo, "支付定金赠送积分"); + + // 4. 记录支付记录 +// recordPaymentLog(orderLog.getOid(), orderLog.getDepLogId(), +// mainOrder.getUid(), mainOrder.getUname(), paymentInfo, "支付" + mainOrder.getProductName() + "服务定金"); + } + + } catch (Exception e) { + logger.error("处理定金支付成功业务逻辑异常:", e); + } + } + + /** + * 处理订单金额支付成功后的业务逻辑 + */ + private void handleOrderAmountPaymentSuccess(Order order, Map paymentInfo) { + try { + // 1. 记录支付成功日志 + logger.info("订单金额支付成功,订单号:{},支付金额:{}", + order.getOrderId(), paymentInfo.get("totalFee")); + + // 2. 更新订单状态为已完成 + order.setStatus(4L); // 4:已结束 + orderService.updateOrder(order); + + // 3. 处理积分奖励(复杂逻辑:考虑定金支付情况) + handleOrderAmountIntegralReward(order, paymentInfo); + + // 4. 记录支付记录 +// recordPaymentLog(order.getId(), order.getOrderId(), +// order.getUid(), order.getUname(), paymentInfo, "支付" + order.getProductName() + "服务尾款"); + recordPaymentLogones(order.getId(),order.getOrderId(),order.getUid(),order.getUname(), paymentInfo, "订单尾款支付"); + + } catch (Exception e) { + logger.error("处理订单金额支付成功业务逻辑异常:", e); + } + } + + /** + * 构建成功响应XML + */ + private String buildSuccessResponse() { + return ""; + } + + /** + * 构建失败响应XML + */ + private String buildFailResponse(String message) { + return ""; + } + + /** + * 根据订单号查找商品订单 + */ + private GoodsOrder findGoodsOrderByOrderId(String orderId) { + GoodsOrder queryOrder = new GoodsOrder(); + queryOrder.setOrderId(orderId); + List orderList = goodsOrderService.selectGoodsOrderList(queryOrder); + return orderList.isEmpty() ? null : orderList.get(0); + } + + /** + * 根据日志订单号查找订单日志 + */ + private OrderLog findOrderLogByLogId(String logId) { + OrderLog queryLog = new OrderLog(); + queryLog.setLogId(logId); + List logList = orderLogService.selectOrderLogList(queryLog); + return logList.isEmpty() ? null : logList.get(0); + } + + /** + * 根据定金订单号查找订单日志 + */ + private OrderLog findOrderLogByDepLogId(String depLogId) { + OrderLog queryLog = new OrderLog(); + queryLog.setDepLogId(depLogId); + List logList = orderLogService.selectOrderLogList(queryLog); + return logList.isEmpty() ? null : logList.get(0); + } + + /** + * 处理积分奖励 + * + * @param paymentInfo 支付信息 + * @param description 描述 + */ + private void handleIntegralReward(Users users,Map paymentInfo, String description) { + + try { + // 1. 查询系统配置 config_one + SiteConfig siteConfigQuery = new SiteConfig(); + siteConfigQuery.setName("config_one"); + List configList = siteConfigService.selectSiteConfigList(siteConfigQuery); + + if (configList.isEmpty()) { + logger.warn("未找到config_one配置,跳过积分奖励"); + return; + } + + SiteConfig config = configList.get(0); + String configValue = config.getValue(); + + if (StringUtils.isEmpty(configValue)) { + logger.warn("config_one配置值为空,跳过积分奖励"); + return; + } + + // 2. 解析JSON获取integral值(积分配置) + Integer integral = null; + try { + JSONObject configJson = JSONObject.parseObject(configValue); + integral = configJson.getInteger("integral"); + } catch (Exception e) { + logger.error("解析config_one配置失败:", e); + return; + } + + if (integral == null || integral <= 0) { + logger.warn("integral配置无效,跳过积分奖励"); + return; + } + + // 3. 计算积分 + String totalFeeStr = (String) paymentInfo.get("totalFee"); + if (StringUtils.isEmpty(totalFeeStr)) { + logger.warn("支付金额为空,跳过积分奖励"); + return; + } + + // 支付金额单位为分,转换为元 + BigDecimal payAmount = new BigDecimal(totalFeeStr).divide(new BigDecimal(100)); + + // 计算积分:实际支付金额除以integral,向下取整 + long integralReward = payAmount.divide(new BigDecimal(integral), 0, BigDecimal.ROUND_DOWN).longValue(); + + // 4. 如果积分大于1,则添加积分记录 + if (integralReward >= 1) { + IntegralLog integralLog = new IntegralLog(); + integralLog.setOrderId(GenerateCustomCode.generCreateOrder("ESTB")); + integralLog.setTitle("支付获得积分"); + integralLog.setMark(description + "获得积分奖励"); + integralLog.setUid(users.getId()); + integralLog.setUname(users.getName()); + integralLog.setType(1L); // 1:增加 + integralLog.setNum(integralReward); + integralLog.setCreatedAt(new Date()); + integralLog.setUpdatedAt(new Date()); + + int result = integralLogService.insertIntegralLog(integralLog); + if (result > 0) { + logger.info("用户{}通过{}获得{}积分", users.getName(), description, integralReward); + } else { + logger.error("添加积分记录失败,订单号:{}", integralLog.getOrderId()); + } + } else { + logger.info("订单{}积分奖励小于1,不予奖励",""); + } + + } catch (Exception e) { + logger.error("处理积分奖励异常,订单号:{},异常信息:", "", e); + } + } + /** + * 记录支付记录单条 + * + * @param paymentInfo 支付信息 + * @param description 描述 + */ + private void recordPaymentLogones(long oid,String orderid,long uid,String uname,Map paymentInfo, String description) { + + try { + String totalFeeStr = (String) paymentInfo.get("totalFee"); + if (StringUtils.isEmpty(totalFeeStr)) { + logger.warn("支付金额为空,跳过支付记录"); + return; + } + PayMoneyLog payMoneyLog = new PayMoneyLog(); + payMoneyLog.setOid(oid); + payMoneyLog.setOrderId(orderid); + payMoneyLog.setUid(uid); + payMoneyLog.setUname(uname); + payMoneyLog.setPrice(new BigDecimal(totalFeeStr)); + payMoneyLog.setMark(description); + payMoneyLog.setPayTime(new Date()); + payMoneyLogService.insertPayMoneyLog(payMoneyLog); + logger.info("用户{}的{}支付记录已保存,金额:{}元", uname, description, totalFeeStr); + + // 支付金额单位为分,转换为元 + // BigDecimal payAmount = new BigDecimal(totalFeeStr).divide(new BigDecimal(100)); + + } catch (Exception e) { + logger.error("记录支付记录异常,订单号:{},异常信息:", oid, e); + } + } + /** + * 记录支付记录多条 + * + * @param paymentInfo 支付信息 + * @param description 描述 + */ + private void recordPaymentLog(String outTradeNo,Map paymentInfo, String description) { + + try { + String totalFeeStr = (String) paymentInfo.get("totalFee"); + if (StringUtils.isEmpty(totalFeeStr)) { + logger.warn("支付金额为空,跳过支付记录"); + return; + } + + // 4. 查询对应的商品订单 + GoodsOrder goodsOrder = new GoodsOrder(); + goodsOrder.setMainOrderId(outTradeNo); + List goodsOrderslist = goodsOrderService.selectGoodsOrderList(goodsOrder); + if (!goodsOrderslist.isEmpty()) { + for (GoodsOrder goodsOrderdata : goodsOrderslist){ + PayMoneyLog payMoneyLog = new PayMoneyLog(); + payMoneyLog.setOid(goodsOrderdata.getId()); + payMoneyLog.setOrderId(goodsOrderdata.getOrderId()); + payMoneyLog.setUid(goodsOrderdata.getUid()); + payMoneyLog.setUname(goodsOrderdata.getUname()); + payMoneyLog.setPrice(goodsOrderdata.getTotalPrice()); + payMoneyLog.setMark(description); + payMoneyLog.setPayTime(new Date()); + payMoneyLogService.insertPayMoneyLog(payMoneyLog); + logger.info("用户{}的{}支付记录已保存,金额:{}元", goodsOrderdata.getUname(), description, goodsOrderdata.getTotalPrice()); + } + } + + // 支付金额单位为分,转换为元 + // BigDecimal payAmount = new BigDecimal(totalFeeStr).divide(new BigDecimal(100)); + + + + + + + + } catch (Exception e) { + logger.error("记录支付记录异常,订单号:{},异常信息:", outTradeNo, e); + } + } + + /** + * 处理订单总金额的积分奖励(考虑定金情况) + * + * @param order 订单信息 + * @param paymentInfo 支付信息 + */ + private void handleOrderAmountIntegralReward(Order order, Map paymentInfo) { + try { + // 1. 查询系统配置 config_one + SiteConfig siteConfigQuery = new SiteConfig(); + siteConfigQuery.setName("config_one"); + List configList = siteConfigService.selectSiteConfigList(siteConfigQuery); + + if (configList.isEmpty()) { + logger.warn("未找到config_one配置,跳过积分奖励"); + return; + } + + SiteConfig config = configList.get(0); + String configValue = config.getValue(); + + if (StringUtils.isEmpty(configValue)) { + logger.warn("config_one配置值为空,跳过积分奖励"); + return; + } + + // 2. 解析JSON获取integral值 + Integer integral = null; + try { + JSONObject configJson = JSONObject.parseObject(configValue); + integral = configJson.getInteger("integral"); + } catch (Exception e) { + logger.error("解析config_one配置失败:", e); + return; + } + + if (integral == null || integral <= 0) { + logger.warn("integral配置无效,跳过积分奖励"); + return; + } + + // 3. 查询是否有定金记录 + OrderLog orderLogQuery = new OrderLog(); + orderLogQuery.setOrderId(order.getOrderId()); + List orderLogList = orderLogService.selectOrderLogList(orderLogQuery); + + BigDecimal totalPrice = BigDecimal.ZERO; + OrderLog depositLog = null; + + // 查找定金记录 + for (OrderLog log : orderLogList) { + if (log.getDeposit() != null && log.getDeposit().compareTo(BigDecimal.ZERO) > 0) { + depositLog = log; + break; + } + } + + // 4. 根据定金情况计算积分基数 + if (depositLog != null && depositLog.getDepPaid() != null) { + if (depositLog.getDepPaid() == 1) { + // 定金未支付/没有定金,直接支付总金额 + totalPrice = depositLog.getPrice(); + } else if (depositLog.getDepPaid() == 2) { + // 定金已支付,计算尾款 + totalPrice = depositLog.getPrice().subtract(depositLog.getDeposit()); + } + } else { + // 没有定金,使用订单总金额 + totalPrice = order.getPayPrice(); + } + + // 5. 计算积分 + long integralReward = totalPrice.divide(new BigDecimal(integral), 0, BigDecimal.ROUND_DOWN).longValue(); + + // 6. 如果积分大于0,则添加积分记录 + if (integralReward > 0) { + IntegralLog integralLog = new IntegralLog(); + integralLog.setOrderId(order.getOrderId()); + integralLog.setTitle("支付服务费用赠送积分"); + integralLog.setMark(order.getProductName() + "服务费用"); + integralLog.setUid(order.getUid()); + integralLog.setUname(order.getUname()); + integralLog.setType(1L); // 1:增加 + integralLog.setNum(integralReward); + integralLog.setCreatedAt(new Date()); + integralLog.setUpdatedAt(new Date()); + + int result = integralLogService.insertIntegralLog(integralLog); + if (result > 0) { + logger.info("用户{}通过服务费用支付获得{}积分", order.getUname(), integralReward); + } else { + logger.error("添加积分记录失败,订单号:{}", order.getOrderId()); + } + } else { + logger.info("订单{}服务费用积分奖励为0,不予奖励", order.getOrderId()); + } + + } catch (Exception e) { + logger.error("处理订单总金额积分奖励异常,订单号:{},异常信息:", order.getOrderId(), e); + } + } + + + + /** + * 分佣 + * + + * @return 商品标题 + */ + public Map calculateCommissionMoney(String orderId,long oid, Long workerId + ) { + // 结果 + Map result = new HashMap<>(); + BigDecimal totalPrice = BigDecimal.ZERO; + BigDecimal margin = BigDecimal.ZERO; + BigDecimal reduction = BigDecimal.ZERO; + BigDecimal servicePrice = BigDecimal.ZERO; + BigDecimal doorPrice = BigDecimal.ZERO; + + // 1. 查询订单日志 + OrderLog orderLogQuery = new OrderLog(); + orderLogQuery.setOrderId(orderId); + List orderLogList = orderLogService.selectOrderLogList(orderLogQuery); + //List orderLogList = orderLogService.selectOrderLogListByWorker(orderId, workerId); + + // 2. 查询订单和商品 + Order order = orderService.selectOrderById(oid); + ServiceGoods product = null; + if (order != null && order.getProductId() != null) { + product = serviceGoodsService.selectServiceGoodsById(order.getProductId()); + } + + // 3. 查询师傅信息 + Users worker = usersService.selectUsersById(workerId); + + // 4. 计算佣金、上门费、优惠金额 + for (OrderLog log : orderLogList) { + if (log.getType() != null && log.getType().intValue() == 5) { + // type=5 评估报价 + WorkerLevel levelInfo = workerLevelService.selectWorkerLevelByLevel(Long.valueOf(worker.getLevel())); + BigDecimal cr = (levelInfo != null && levelInfo.getCr() != null) ? new BigDecimal(levelInfo.getCr()).divide(new BigDecimal(100)) : BigDecimal.ZERO; + totalPrice = totalPrice.add(log.getWorkerCost().multiply(cr).setScale(2, BigDecimal.ROUND_HALF_UP)); + servicePrice = log.getWorkerCost().add(log.getReductionPrice() != null ? log.getReductionPrice() : BigDecimal.ZERO); + } + if (log.getType() != null && log.getType().intValue() == 2) { + // type=2 上门费 + totalPrice = totalPrice.add(log.getWorkerCost()); + doorPrice = log.getWorkerCost(); + } + if (log.getReductionPrice() != null) { + reduction = reduction.add(log.getReductionPrice()); + } + } + + // 5. 判断是否需要扣除质保金 + if (product != null && product.getMargin() != null && worker != null && worker.getMargin() != null + && product.getMargin().compareTo(worker.getMargin()) > 0) { + // 查系统配置 + SiteConfig config = siteConfigService.selectSiteConfigByName("config_one"); + BigDecimal marginPercent = BigDecimal.ZERO; + if (config != null && config.getValue() != null) { + try { + JSONObject json = JSONObject.parseObject(config.getValue()); + if (json.containsKey("margin")) { + marginPercent = new BigDecimal(json.getString("margin")).divide(new BigDecimal(100)); + } + } catch (Exception ignore) {} + } + margin = totalPrice.multiply(marginPercent).setScale(2, BigDecimal.ROUND_HALF_UP); + // 超过质保金,则扣少点 + if (worker.getMargin().add(margin).compareTo(product.getMargin()) > 0) { + margin = product.getMargin().subtract(worker.getMargin()); + } + // 插入质保金明细 + WorkerMarginLog marginLog = new WorkerMarginLog(); + marginLog.setOid(order.getId()); + marginLog.setUid(workerId); + marginLog.setOrderId(order != null ? order.getOrderId() : null); + marginLog.setPrice(margin); +// marginLog.setCreatedAt(new Date()); +// marginLog.setUpdatedAt(new Date()); + workerMarginLogService.insertWorkerMarginLog(marginLog); + } + + // 6. 返回 + result.put("commission", totalPrice); + result.put("margin", margin); + result.put("reduction", reduction); + result.put("service_price", servicePrice); + result.put("door_price", doorPrice); + return result; + } + + + + + /** + * 获取商品标题 + * + * @param goodsOrder 商品订单 + * @return 商品标题 + */ + private String getGoodsTitle(GoodsOrder goodsOrder) { + try { + // 这里应该查询商品信息,简化处理返回商品名称或默认值 + if (goodsOrder.getProductName() != null) { + return goodsOrder.getProductName(); + } + return "商品"; + } catch (Exception e) { + logger.error("获取商品标题异常:", e); + return "商品"; + } + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/AppletControllerUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/AppletControllerUtil.java index 2acbb0e..ec2e412 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/AppletControllerUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/AppletControllerUtil.java @@ -2,8 +2,11 @@ package com.ruoyi.system.ControllerUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.system.domain.*; +import com.ruoyi.system.service.IGoodsCartService; import com.ruoyi.system.service.IServiceGoodsService; import com.ruoyi.system.service.IUserAddressService; import com.ruoyi.system.service.IUsersService; @@ -2573,11 +2576,11 @@ public class AppletControllerUtil { * @param goodsCartService 购物车服务 * @return 添加结果 */ - public static com.ruoyi.common.core.domain.AjaxResult addNewCartItem( - com.ruoyi.system.domain.Users user, - com.ruoyi.system.domain.ServiceGoods serviceGoods, + public static AjaxResult addNewCartItem( + Users user, + ServiceGoods serviceGoods, String sku, - com.ruoyi.system.service.IGoodsCartService goodsCartService) { + IGoodsCartService goodsCartService) { try { // 构建购物车记录 com.ruoyi.system.domain.GoodsCart newCartItem = new com.ruoyi.system.domain.GoodsCart(); @@ -2618,7 +2621,7 @@ public class AppletControllerUtil { if (serviceGoods != null) { goodInfo.put("id", serviceGoods.getId()); goodInfo.put("title", serviceGoods.getTitle()); - goodInfo.put("price", serviceGoods.getPriceZn()); + goodInfo.put("price", serviceGoods.getPrice()); goodInfo.put("price_zn", serviceGoods.getPriceZn()); goodInfo.put("icon", buildImageUrl(serviceGoods.getIcon())); goodInfo.put("stock", serviceGoods.getStock()); @@ -2996,7 +2999,7 @@ public class AppletControllerUtil { try { // 尝试解析为JSON对象 - com.alibaba.fastjson2.JSONObject skuJson = com.alibaba.fastjson2.JSONObject.parseObject(sku); + JSONObject skuJson = JSONObject.parseObject(sku); return skuJson.toJavaObject(Map.class); } catch (Exception e) { // 解析失败,返回null @@ -3004,6 +3007,76 @@ public class AppletControllerUtil { } } + /** + * 将字符串转换为JSON对象(通用工具方法) + * + * 支持将JSON字符串转换为Map对象 + * 如果字符串为空或解析失败,返回null + * + * @param jsonString JSON字符串 + * @return JSON对象,解析失败返回null + */ + public static Map parseStringToJson(String jsonString) { + if (jsonString == null || jsonString.trim().isEmpty()) { + return null; + } + + try { + // 预处理字符串,移除可能的特殊字符 + String cleanJsonString = cleanJsonString(jsonString); + + // 尝试解析为JSON对象 + JSONObject jsonObject = JSONObject.parseObject(cleanJsonString); + return jsonObject.toJavaObject(Map.class); + } catch (Exception e) { + // 解析失败,打印详细错误信息并返回null + System.err.println("JSON解析失败,原始字符串: [" + jsonString + "], 错误: " + e.getMessage()); + return null; + } + } + + /** + * 清理JSON字符串,移除可能导致解析失败的字符 + * + * @param jsonString 原始JSON字符串 + * @return 清理后的JSON字符串 + */ + private static String cleanJsonString(String jsonString) { + if (jsonString == null) { + return null; + } + + // 移除BOM字符 + if (jsonString.startsWith("\uFEFF")) { + jsonString = jsonString.substring(1); + } + + // 去除首尾空白字符 + jsonString = jsonString.trim(); + + // 如果不是以{或[开头,可能不是有效的JSON + if (!jsonString.startsWith("{") && !jsonString.startsWith("[")) { + return "{}"; // 返回空对象 + } + + return jsonString; + } + + /** + * 将字符串转换为JSON对象(带默认值) + * + * 支持将JSON字符串转换为Map对象 + * 如果字符串为空或解析失败,返回提供的默认值 + * + * @param jsonString JSON字符串 + * @param defaultValue 解析失败时的默认值 + * @return JSON对象,解析失败返回默认值 + */ + public static Map parseStringToJson(String jsonString, Map defaultValue) { + Map result = parseStringToJson(jsonString); + return result != null ? result : defaultValue; + } + /** * 格式化日期为字符串 * @@ -3017,4 +3090,28 @@ public class AppletControllerUtil { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(date); } + + /** + * 处理SKU参数,确保以JSON字符串格式存储 + * @param skuParam 前端传递的SKU参数 + * @return JSON字符串格式的SKU + */ + public static String processSkuParam(Object skuParam) { + if (skuParam == null) { + return ""; + } + + if (skuParam instanceof Map) { + // 如果是Map对象,转换为JSON字符串 + try { + return com.alibaba.fastjson2.JSON.toJSONString(skuParam); + } catch (Exception e) { + System.err.println("SKU转换JSON失败:" + e.getMessage()); + return skuParam.toString(); + } + } else { + // 如果是字符串,直接使用 + return skuParam.toString().trim(); + } + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/OrderBindWorkerUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/OrderBindWorkerUtil.java index 516f8d4..e38e8af 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/OrderBindWorkerUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/OrderBindWorkerUtil.java @@ -102,6 +102,7 @@ public class OrderBindWorkerUtil { // 8. 绑定中间号,直到成功 for (MobileMiddle middle : mobileMiddleList) { VoiceResponseResult bindResult = YunXinPhoneUtilAPI.httpsPrivacyBindAxb(middle.getPhone(), userPhone, workerPhone); + System.out.println(middle.getPhone()+"__________"+userPhone+"__________"+workerPhone); if ("000000".equals(bindResult.getResult())) { // 绑定成功,更新订单 order.setMiddlePhone(middle.getPhone()); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WXsendMsgUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WXsendMsgUtil.java index 4329b4b..a7a1e27 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WXsendMsgUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WXsendMsgUtil.java @@ -15,6 +15,7 @@ import com.alibaba.fastjson2.JSONObject; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.domain.AppleDoMain.TemplateData; import com.ruoyi.system.domain.AppleDoMain.WxMssVo; +import com.ruoyi.system.domain.GoodsOrder; import com.ruoyi.system.domain.Order; import com.ruoyi.system.domain.ServiceGoods; import org.springframework.http.ResponseEntity; @@ -291,5 +292,52 @@ public class WXsendMsgUtil { wxMssVo.setData(m); return PublicPush(wxMssVo); } + //用户支付上门费后向师傅进行推送 + public static String sendUserPayDoorMoneyForWorker(String openid, Order order, ServiceGoods serviceGoods) throws Exception { + // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + //拼接推送的模版 + WxMssVo wxMssVo = new WxMssVo(); + wxMssVo.setTouser(openid);//用户的openid(要发送给那个用户,通常这里应该动态传进来的) + wxMssVo.setTemplate_id(ORDER_STATUS);//订阅消息模板id + wxMssVo.setPage("/pages/serveSF/home/details?id="+order.getId()); +// String mark = order.getMark(); +// if (StringUtils.isEmpty( mark)){ +// mark="暂无备注"; +// } + Map m = new HashMap<>(3); + m.put("thing15", new TemplateData(serviceGoods.getTitle())); + m.put("character_string5", new TemplateData(order.getOrderId())); + m.put("date3", new TemplateData(AppletControllerUtil.timeStamp2Date(order))); + m.put("thing1", new TemplateData(order.getAddress())); + m.put("thing9", new TemplateData("用户已支付上门费")); + + System.out.println("师傅设置上门费的时候的推送:" + m.toString()); + wxMssVo.setData(m); + return PublicPush(wxMssVo); + } + + //客户支付成功的消息推送 + public static String sendUserForMoneySuccess(String openid, GoodsOrder order, ServiceGoods serviceGoods) throws Exception { + // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + //拼接推送的模版 + WxMssVo wxMssVo = new WxMssVo(); + wxMssVo.setTouser(openid);//用户的openid(要发送给那个用户,通常这里应该动态传进来的) + wxMssVo.setTemplate_id(PAY_GOODS);//订阅消息模板id + wxMssVo.setPage("/pages/mine/shopOrder/index"); + String mark = order.getMark(); + if (StringUtils.isEmpty( mark)){ + mark="暂无备注"; + } + Map m = new HashMap<>(3); + m.put("thing11", new TemplateData(serviceGoods.getTitle())); + m.put("character_string3", new TemplateData(order.getOrderId())); + m.put("amount27",new TemplateData(String.valueOf(order.getTotalPrice()))); + m.put("thing1", new TemplateData(order.getAddress())); + m.put("thing9", new TemplateData("师傅已经已经接单")); + + System.out.println("师傅设置上门费的时候的推送:" + m.toString()); + wxMssVo.setData(m); + return PublicPush(wxMssVo); + } } \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WechatPayUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WechatPayUtil.java index 3bf259f..12b1751 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WechatPayUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WechatPayUtil.java @@ -78,9 +78,24 @@ public class WechatPayUtil { private static final String FAIL_CODE = "FAIL"; /** - * RestTemplate实例 + * RestTemplate实例(配置UTF-8编码) */ - private static final RestTemplate restTemplate = new RestTemplate(); + private static final RestTemplate restTemplate = createRestTemplate(); + + /** + * 创建配置了UTF-8编码的RestTemplate实例 + */ + private static RestTemplate createRestTemplate() { + RestTemplate template = new RestTemplate(); + // 设置字符编码为UTF-8,解决中文乱码问题 + template.getMessageConverters().forEach(converter -> { + if (converter instanceof org.springframework.http.converter.StringHttpMessageConverter) { + ((org.springframework.http.converter.StringHttpMessageConverter) converter) + .setDefaultCharset(StandardCharsets.UTF_8); + } + }); + return template; + } @@ -113,11 +128,13 @@ public class WechatPayUtil { if (notifyUrl == null || notifyUrl.trim().isEmpty()) { return failResult("回调通知地址不能为空"); } + // 2. 构建参数 Map params = new HashMap<>(); params.put("appid", wechatAppId); params.put("mch_id", wechatMchId); - params.put("nonce_str", generateNonceStr()); + String nonceStr = generateNonceStr(); + params.put("nonce_str", nonceStr); params.put("body", body); params.put("out_trade_no", orderNo); params.put("total_fee", String.valueOf(totalFee)); // 单位:分 @@ -128,27 +145,52 @@ public class WechatPayUtil { if (attach != null && !attach.trim().isEmpty()) { params.put("attach", attach); } + // 3. 生成签名 String sign = generateSign(params, wechatApiKey); params.put("sign", sign); + // 4. 发送请求 String xmlRequest = mapToXml(params); - ResponseEntity response = restTemplate.postForEntity(WECHAT_PAY_URL, xmlRequest, String.class); + + // 设置请求头,指定字符编码为UTF-8 + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "application/xml;charset=UTF-8"); + headers.set("Accept", "application/xml;charset=UTF-8"); + headers.set("User-Agent", "Mozilla/5.0"); + + HttpEntity requestEntity = new HttpEntity<>(xmlRequest, headers); + ResponseEntity response = restTemplate.exchange(WECHAT_PAY_URL, HttpMethod.POST, requestEntity, String.class); + + // 5. 解析响应 Map responseMap = xmlToMap(response.getBody()); - // 5. 处理响应 - if (SUCCESS_CODE.equals(responseMap.get("return_code")) && SUCCESS_CODE.equals(responseMap.get("result_code"))) { - // 6. 构建小程序端调起支付参数 - Map payParams = buildMiniProgramPayParams(responseMap.get("prepay_id")); + + // 6. 处理响应 + String returnCode = responseMap.get("return_code"); + String resultCode = responseMap.get("result_code"); + + if (SUCCESS_CODE.equals(returnCode) && SUCCESS_CODE.equals(resultCode)) { + String prepayId = responseMap.get("prepay_id"); + + // 7. 构建小程序端调起支付参数 + Map payParams = buildMiniProgramPayParams(prepayId); + result.put("success", true); result.put("payParams", payParams); - result.put("prepayId", responseMap.get("prepay_id")); + result.put("prepayId", prepayId); result.put("message", "统一下单成功"); } else { - result = failResult("统一下单失败:" + (responseMap.get("err_code_des") != null ? responseMap.get("err_code_des") : responseMap.get("return_msg"))); + String errorCode = responseMap.get("err_code"); + String errorCodeDes = responseMap.get("err_code_des"); + String returnMsg = responseMap.get("return_msg"); + + String errorMessage = "统一下单失败:" + (errorCodeDes != null ? errorCodeDes : returnMsg); + result = failResult(errorMessage); } } catch (Exception e) { result = failResult("统一下单异常:" + e.getMessage()); } + return result; } @@ -177,7 +219,15 @@ public class WechatPayUtil { String sign = generateSign(params, wechatApiKey); params.put("sign", sign); String xmlRequest = mapToXml(params); - ResponseEntity response = restTemplate.postForEntity(WECHAT_QUERY_URL, xmlRequest, String.class); + + // 设置请求头,指定字符编码为UTF-8解决中文乱码 + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "application/xml;charset=UTF-8"); + headers.set("Accept", "application/xml;charset=UTF-8"); + headers.set("User-Agent", "Mozilla/5.0"); + + HttpEntity requestEntity = new HttpEntity<>(xmlRequest, headers); + ResponseEntity response = restTemplate.exchange(WECHAT_QUERY_URL, HttpMethod.POST, requestEntity, String.class); Map responseMap = xmlToMap(response.getBody()); if (SUCCESS_CODE.equals(responseMap.get("return_code")) && SUCCESS_CODE.equals(responseMap.get("result_code"))) { Map orderInfo = new HashMap<>(); @@ -365,6 +415,58 @@ public class WechatPayUtil { return result; } + /** + * 批量订单统一下单并返回前端支付参数(用于多商品批量下单场景) + * @param openid 用户openid + * @param mainOrderId 主订单号 + * @param totalAmount 总金额(单位:元) + * @param orderCount 订单数量 + * @return Map,包含支付参数和下单结果 + */ + public Map createBatchOrderAndPay(String openid, String mainOrderId, BigDecimal totalAmount, int orderCount,String notifyUrl) { + Map result = new HashMap<>(); + try { + if (openid == null || openid.trim().isEmpty()) { + return failResult("用户openid为空,无法发起支付"); + } + if (mainOrderId == null || mainOrderId.trim().isEmpty()) { + return failResult("主订单号不能为空"); + } + if (totalAmount == null || totalAmount.compareTo(BigDecimal.ZERO) <= 0) { + return failResult("支付金额必须大于0"); + } + // 金额转换为分 + int totalFeeInCents = totalAmount.multiply(new BigDecimal(100)).intValue(); + String body = "批量订单-" + orderCount + "个商品"; + //String notifyUrl =notifyUrl; + //String notifyUrl = "https://4d983d7f.r3.cpolar.top/api/goods/pay/notify"; + String attach = "batch_order:" + mainOrderId; + + Map payResult = unifiedOrder( + openid, + mainOrderId, + totalFeeInCents, + body, + notifyUrl, + attach + ); + if (payResult != null && Boolean.TRUE.equals(payResult.get("success"))) { + Map payParams = (Map) payResult.get("payParams"); + result.put("success", true); + result.put("prepayId", payResult.get("prepayId")); + if (payParams != null) { + result.putAll(payParams); + } + } else { + String errorMsg = payResult != null ? (String) payResult.get("message") : "微信支付下单失败"; + return failResult(errorMsg); + } + } catch (Exception e) { + return failResult("批量订单微信支付异常:" + e.getMessage()); + } + return result; + } + // ===================== 工具方法和签名相关 ===================== /** @@ -378,6 +480,7 @@ public class WechatPayUtil { String nonceStr = generateNonceStr(); String packageStr = "prepay_id=" + prepayId; String signType = "MD5"; + // 构建签名参数 Map signParams = new HashMap<>(); signParams.put("appId", wechatAppId); @@ -385,12 +488,15 @@ public class WechatPayUtil { signParams.put("nonceStr", nonceStr); signParams.put("package", packageStr); signParams.put("signType", signType); + String paySign = generateSign(signParams, wechatApiKey); + payParams.put("timeStamp", timeStamp); payParams.put("nonceStr", nonceStr); payParams.put("package", packageStr); payParams.put("signType", signType); payParams.put("paySign", paySign); + return payParams; } @@ -410,12 +516,15 @@ public class WechatPayUtil { } } stringBuilder.append("key=").append(key); + + String signString = stringBuilder.toString(); MessageDigest md5 = MessageDigest.getInstance("MD5"); - byte[] digest = md5.digest(stringBuilder.toString().getBytes(StandardCharsets.UTF_8)); + byte[] digest = md5.digest(signString.getBytes(StandardCharsets.UTF_8)); StringBuilder result = new StringBuilder(); for (byte b : digest) { result.append(String.format("%02X", b)); } + return result.toString(); } catch (Exception e) { throw new RuntimeException("生成签名失败", e); @@ -446,6 +555,8 @@ public class WechatPayUtil { */ private String mapToXml(Map params) { StringBuilder xml = new StringBuilder(); + // 添加XML声明,指定UTF-8编码 + xml.append(""); xml.append(""); for (Map.Entry entry : params.entrySet()) { xml.append("<").append(entry.getKey()).append("> xmlToMap(String xml) { Map map = new HashMap<>(); try { - xml = xml.replaceAll("", "").replaceAll("", ""); - String[] elements = xml.split(""); + // 移除XML声明和根标签 + String processedXml = xml.replaceAll("<\\?xml[^>]*\\?>", "") + .replaceAll("", "") + .replaceAll("", ""); + + String[] elements = processedXml.split(""); + for (String element : elements) { - if (element.trim().isEmpty()) continue; + if (element.trim().isEmpty()) { + continue; + } + int startTag = element.indexOf("<"); int endTag = element.indexOf(">"); if (startTag >= 0 && endTag > startTag) { String key = element.substring(startTag + 1, endTag); String value = element.substring(endTag + 1); + if (value.startsWith("")) { value = value.substring(9, value.length() - 3); } + map.put(key, value); } } + } catch (Exception e) { throw new RuntimeException("XML解析失败", e); } @@ -656,4 +778,4 @@ public class WechatPayUtil { return params; } -} \ No newline at end of file +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/Order.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/Order.java index febe690..bb0bf14 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/Order.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/Order.java @@ -143,8 +143,8 @@ public class Order extends BaseEntity private Long firstWorkerId; /** 接单时间 */ - @JsonFormat(pattern = "yyyy-MM-dd") - @Excel(name = "接单时间", width = 30, dateFormat = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "接单时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") private Date receiveTime; /** 1:已评价 0:未评价 */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SiteConfigMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SiteConfigMapper.java index 19b722c..2ee3d32 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SiteConfigMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SiteConfigMapper.java @@ -19,6 +19,8 @@ public interface SiteConfigMapper */ public SiteConfig selectSiteConfigById(Integer id); + public SiteConfig selectSiteConfigByName(String name); + /** * 查询系统配置列表 * diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/WorkerLevelMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/WorkerLevelMapper.java index 3f784fe..b97b931 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/WorkerLevelMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/WorkerLevelMapper.java @@ -19,6 +19,9 @@ public interface WorkerLevelMapper */ public WorkerLevel selectWorkerLevelById(Long id); + public WorkerLevel selectWorkerLevelByLevel(Long level); + + /** * 查询师傅等级配置列表 * diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISiteConfigService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISiteConfigService.java index decdd1b..865cf3d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISiteConfigService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISiteConfigService.java @@ -18,7 +18,7 @@ public interface ISiteConfigService * @return 系统配置 */ public SiteConfig selectSiteConfigById(Integer id); - + public SiteConfig selectSiteConfigByName(String name); /** * 查询系统配置列表 * diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IWorkerLevelService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IWorkerLevelService.java index ef6d179..6f3e807 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IWorkerLevelService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IWorkerLevelService.java @@ -18,7 +18,7 @@ public interface IWorkerLevelService * @return 师傅等级配置 */ public WorkerLevel selectWorkerLevelById(Long id); - + public WorkerLevel selectWorkerLevelByLevel(Long level); /** * 查询师傅等级配置列表 * diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SiteConfigServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SiteConfigServiceImpl.java index 942fb09..f5e74ac 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SiteConfigServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SiteConfigServiceImpl.java @@ -31,6 +31,11 @@ public class SiteConfigServiceImpl implements ISiteConfigService return siteConfigMapper.selectSiteConfigById(id); } + + public SiteConfig selectSiteConfigByName(String name) { + return siteConfigMapper.selectSiteConfigByName(name); + + } /** * 查询系统配置列表 * diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WorkerLevelServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WorkerLevelServiceImpl.java index 762e7c0..1f39e6e 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WorkerLevelServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WorkerLevelServiceImpl.java @@ -19,6 +19,11 @@ public class WorkerLevelServiceImpl implements IWorkerLevelService @Autowired private WorkerLevelMapper workerLevelMapper; + + public WorkerLevel selectWorkerLevelByLevel(Long level) { + + return workerLevelMapper.selectWorkerLevelByLevel(level); + } /** * 查询师傅等级配置 * diff --git a/ruoyi-system/src/main/resources/mapper/system/OrderLogMapper.xml b/ruoyi-system/src/main/resources/mapper/system/OrderLogMapper.xml index eb9f136..99c8aa6 100644 --- a/ruoyi-system/src/main/resources/mapper/system/OrderLogMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/OrderLogMapper.xml @@ -84,7 +84,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" diff --git a/ruoyi-system/src/main/resources/mapper/system/SiteConfigMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SiteConfigMapper.xml index c3307e3..e400811 100644 --- a/ruoyi-system/src/main/resources/mapper/system/SiteConfigMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/SiteConfigMapper.xml @@ -30,6 +30,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where id = #{id} + insert into site_config diff --git a/ruoyi-system/src/main/resources/mapper/system/WorkerLevelMapper.xml b/ruoyi-system/src/main/resources/mapper/system/WorkerLevelMapper.xml index 5d820fb..518052c 100644 --- a/ruoyi-system/src/main/resources/mapper/system/WorkerLevelMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/WorkerLevelMapper.xml @@ -47,6 +47,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where id = #{id} + insert into worker_level