diff --git a/eride-admin/src/main/java/com/ruoyi/web/controller/app/AppController.java b/eride-admin/src/main/java/com/ruoyi/web/controller/app/AppController.java index 8efe708..ef9d64d 100644 --- a/eride-admin/src/main/java/com/ruoyi/web/controller/app/AppController.java +++ b/eride-admin/src/main/java/com/ruoyi/web/controller/app/AppController.java @@ -385,7 +385,7 @@ public class AppController extends BaseController public AjaxResult getDeviceInfoByMacList(String[] macList) { if(ObjectUtil.isNull(macList)){ - logger.info("没有mac号数组参数:【macList={}】",macList); + logger.info("没有mac号数组参数:【macList={}】",JSON.toJSONString(macList)); return error("未传mac号参数"); } ArrayList asDevices = new ArrayList<>(); diff --git a/eride-admin/src/main/java/com/ruoyi/web/controller/app/AppVerifyController.java b/eride-admin/src/main/java/com/ruoyi/web/controller/app/AppVerifyController.java index cbc64de..440f16b 100644 --- a/eride-admin/src/main/java/com/ruoyi/web/controller/app/AppVerifyController.java +++ b/eride-admin/src/main/java/com/ruoyi/web/controller/app/AppVerifyController.java @@ -20,6 +20,10 @@ import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.ServiceUtil; import com.ruoyi.common.utils.verify.vo.IDResponse; import com.ruoyi.common.utils.wx.vo.PrepayResponseVO; +import com.ruoyi.e.order.domain.order.EOrder; +import com.ruoyi.e.order.domain.order.EOrderQuery; +import com.ruoyi.e.order.domain.order.EOrderVO; +import com.ruoyi.e.order.domain.order.dto.EOrderDTO; import com.ruoyi.e.order.domain.order.dto.EReletOrderDTO; import com.ruoyi.e.order.service.IEOrderService; import com.ruoyi.framework.web.service.TokenService; @@ -37,10 +41,6 @@ import com.ruoyi.system.domain.device.EDeviceVO; import com.ruoyi.system.domain.model.EModelQuery; import com.ruoyi.system.domain.model.EModelVO; import com.ruoyi.system.domain.modelAccessory.EModelAccessory; -import com.ruoyi.e.order.domain.order.EOrder; -import com.ruoyi.e.order.domain.order.EOrderQuery; -import com.ruoyi.e.order.domain.order.EOrderVO; -import com.ruoyi.e.order.domain.order.dto.EOrderDTO; import com.ruoyi.system.domain.query.AuthenticationQuery; import com.ruoyi.system.domain.rule.EFeeRule; import com.ruoyi.system.domain.userWithdraw.EUserWithdraw; @@ -49,7 +49,6 @@ import com.ruoyi.system.domain.withdraw.EWithdrawQuery; import com.ruoyi.system.service.*; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.transaction.support.TransactionTemplate; import org.springframework.web.bind.annotation.*; @@ -57,6 +56,9 @@ import javax.annotation.Resource; import java.math.BigDecimal; import java.util.List; +import static com.ruoyi.common.constant.ServiceConstants.USER_TYPE_INDIVIDUAL; +import static com.ruoyi.common.constant.ServiceConstants.USER_TYPE_MERCHANT; + /** * app接口(需要登录校验的) * 校验 @@ -296,7 +298,7 @@ public class AppVerifyController extends BaseController if(StrUtil.isBlank(vehicleNum)){ return error("【更新车牌号】车牌号不能为空"); } - EDevice rlDevice = deviceService.selectEDeviceBySn(sn); + EDeviceVO rlDevice = deviceService.selectEDeviceBySn(sn); if(rlDevice == null){ return error("【更新车牌号】设备不存在【"+sn+"】"); } @@ -616,7 +618,7 @@ public class AppVerifyController extends BaseController @PostMapping("/band") public AjaxResult bandSn(String sn,String mac,Long hardwareVersionId) { - logger.info("sn和mac号绑定:【sn="+sn+"】,【mac="+mac+"】,【hardwareVersionId="+hardwareVersionId+"】"); + logger.info("sn和mac号绑定:【sn={}】,【mac={}】,【hardwareVersionId={}】", sn, mac, hardwareVersionId); EDevice asDevice = new EDevice(); asDevice.setSn(sn); asDevice.setMac(mac); @@ -821,7 +823,8 @@ public class AppVerifyController extends BaseController { logger.info("【根据token查询车辆列表(商家)】:keywords= {}", keywords); EUserVO userVO = userService.selectUserById(getUserId()); - ServiceUtil.assertion(!userVO.getUserType().equals(ServiceConstants.USER_TYPE_MERCHANT), "您没有权限访问"); + String userType = userVO.getUserType(); + ServiceUtil.assertion(!(userType.equals(USER_TYPE_MERCHANT) || userType.equals(USER_TYPE_INDIVIDUAL)), "您没有权限访问"); EDeviceQuery deviceQuery = new EDeviceQuery(); deviceQuery.setUserId(getUserId()); deviceQuery.setKeywords(keywords); @@ -1095,4 +1098,15 @@ public class AppVerifyController extends BaseController return toAjax(i); } + /** + * 退款 + */ + @Log(title = "订单退款", businessType = BusinessType.REFUND) + @PutMapping("/refund") + public AjaxResult orderRefund(@RequestBody EOrderQuery etOrder) + { + logger.info("【订单退款请求】:{}", JSON.toJSON(etOrder)); + return toAjax(orderService.refund(etOrder)); + } + } diff --git a/eride-admin/src/main/java/com/ruoyi/web/controller/common/CallbackController.java b/eride-admin/src/main/java/com/ruoyi/web/controller/common/CallbackController.java index 135cadd..e3f1ef4 100644 --- a/eride-admin/src/main/java/com/ruoyi/web/controller/common/CallbackController.java +++ b/eride-admin/src/main/java/com/ruoyi/web/controller/common/CallbackController.java @@ -1,6 +1,13 @@ package com.ruoyi.web.controller.common; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.common.constant.ServiceConstants; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.pay.tm.TmPayService; +import com.ruoyi.common.pay.tm.enums.PayStatus; import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.http.HttpUtils; import com.ruoyi.system.domain.EtCallbackLog; import com.ruoyi.system.mapper.ECallbackLogMapper; import com.ruoyi.system.service.CallbackService; @@ -16,6 +23,7 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; +import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -30,8 +38,8 @@ public class CallbackController { @Autowired private CallbackService callbackService; -// @Autowired -// private TmPayService tmPayService; + @Autowired + private TmPayService tmPayService; @Autowired private ScheduledExecutorService scheduledExecutorService; @@ -71,44 +79,44 @@ public class CallbackController { return ResponseEntity.status(HttpStatus.OK).body(null); } -// /** -// * 太米微信支付回调 -// */ -// @ApiOperation(value = "太米微信支付回调") -// @RequestMapping(value = "/tmwx", method = RequestMethod.POST) -// public String tmwx(HttpServletRequest request) { -// try { -// String body = HttpUtils.getBody(request); -// log.info("【太米微信支付回调】接收对象 : " + body); -// // 先把body转成map -// Map params = JSON.parseObject(body, Map.class); -// // 验证签名 -// boolean sign = tmPayService.validSign(params); -// if (sign) { -// EtCallbackLog etCallbackLog = new EtCallbackLog(); -// etCallbackLog.setBody(body); -// etCallbackLog.setType("1"); -// JSONObject tradeInfo = (JSONObject)params.get("tradeInfo"); -// String payType = (String)tradeInfo.get("payType"); // 交易类型 -// String outTradeNo = (String)tradeInfo.get("outTradeId"); // 商户自定义订单号 -// String trxStatus = (String)tradeInfo.get("payStatus"); // 交易结果 + /** + * 太米微信支付回调 + */ + @ApiOperation(value = "太米微信支付回调") + @RequestMapping(value = "/tmwx", method = RequestMethod.POST) + public String tmwx(HttpServletRequest request) { + try { + String body = HttpUtils.getBody(request); + log.info("【太米微信支付回调】接收对象 : {}", body); + // 先把body转成map + Map params = JSON.parseObject(body, Map.class); + // 验证签名 + boolean sign = tmPayService.validSign(params); + if (sign) { + EtCallbackLog etCallbackLog = new EtCallbackLog(); + etCallbackLog.setBody(body); + etCallbackLog.setType("1"); + JSONObject tradeInfo = (JSONObject)params.get("tradeInfo"); + String payType = (String)tradeInfo.get("payType"); // 交易类型 + String outTradeNo = (String)tradeInfo.get("outTradeId"); // 商户自定义订单号 + String trxStatus = (String)tradeInfo.get("payStatus"); // 交易结果 // // 构建attachVo // AttachVo attach = generateAttach(outTradeNo); // log.info("【太米微信支付回调】创建的attachVo : " + JSON.toJSONString(attach)); -// if(PayStatus.isSuccess(trxStatus) && payType.equals("wx_pay")) { -// // 新版支付订单 -// callbackService.businessHandle(outTradeNo,attach, ServiceConstants.PAY_TYPE_TMWX); -// } -// //异步保存回调日志 -// asynchronousSaveCallbackLog(etCallbackLog);// tradeInfo -> {JSONObject@14208} size = 34 -// }else { -// throw new ServiceException("签名验证失败"); -// } -// return "{\"result\":\"SUCCESS\"}"; -// } catch (Exception e) { -// throw new ServiceException(e.getMessage()); -// } -// } + if(PayStatus.isSuccess(trxStatus) && payType.equals("wx_pay")) { + // 新版支付订单 + callbackService.businessHandle(outTradeNo, ServiceConstants.PAY_TYPE_TMWX); + } + //异步保存回调日志 + asynchronousSaveCallbackLog(etCallbackLog);// tradeInfo -> {JSONObject@14208} size = 34 + }else { + throw new ServiceException("签名验证失败"); + } + return "{\"result\":\"SUCCESS\"}"; + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } private void asynchronousSaveCallbackLog(EtCallbackLog etCallbackLog) { diff --git a/eride-admin/src/main/java/com/ruoyi/web/controller/system/EOrderController.java b/eride-admin/src/main/java/com/ruoyi/web/controller/system/EOrderController.java index dfcb456..348b63b 100644 --- a/eride-admin/src/main/java/com/ruoyi/web/controller/system/EOrderController.java +++ b/eride-admin/src/main/java/com/ruoyi/web/controller/system/EOrderController.java @@ -1,5 +1,6 @@ package com.ruoyi.web.controller.system; +import com.alibaba.fastjson2.JSON; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; @@ -28,7 +29,7 @@ import java.util.List; public class EOrderController extends BaseController { @Autowired - private IEOrderService rlOrderService; + private IEOrderService orderService; /** * 查询订单列表 @@ -38,7 +39,7 @@ public class EOrderController extends BaseController public TableDataInfo list(EOrderQuery rlOrder) { startPage(); - List list = rlOrderService.selectRlOrderList(rlOrder); + List list = orderService.selectRlOrderList(rlOrder); return getDataTable(list); } @@ -50,7 +51,7 @@ public class EOrderController extends BaseController @PostMapping("/export") public void export(HttpServletResponse response, EOrderQuery rlOrder) { - List list = rlOrderService.selectRlOrderList(rlOrder); + List list = orderService.selectRlOrderList(rlOrder); ExcelUtil util = new ExcelUtil(EOrderVO.class); util.exportExcel(response, list, "订单数据"); } @@ -62,7 +63,7 @@ public class EOrderController extends BaseController @GetMapping(value = "/{orderId}") public AjaxResult getInfo(@PathVariable("orderId") Long orderId) { - return success(rlOrderService.selectRlOrderByOrderId(orderId)); + return success(orderService.selectRlOrderByOrderId(orderId)); } /** @@ -73,7 +74,7 @@ public class EOrderController extends BaseController @PostMapping public AjaxResult add(@RequestBody EOrderQuery rlOrder) { - return toAjax(rlOrderService.insertRlOrder(rlOrder)); + return toAjax(orderService.insertRlOrder(rlOrder)); } /** @@ -84,17 +85,19 @@ public class EOrderController extends BaseController @PutMapping public AjaxResult edit(@RequestBody EOrder rlOrder) { - return toAjax(rlOrderService.updateRlOrder(rlOrder)); + return toAjax(orderService.updateRlOrder(rlOrder)); } + /** - * 删除订单 + * 退款 */ - @PreAuthorize("@ss.hasPermi('system:order:remove')") - @Log(title = "订单", businessType = BusinessType.DELETE) - @DeleteMapping("/{orderIds}") - public AjaxResult remove(@PathVariable Long[] orderIds) + @PreAuthorize("@ss.hasPermi('system:order:refund')") + @Log(title = "订单退款", businessType = BusinessType.REFUND) + @PutMapping("/refund") + public AjaxResult orderRefund(@RequestBody EOrderQuery etOrder) { - return toAjax(rlOrderService.deleteRlOrderByOrderIds(orderIds)); + logger.info("【订单退款请求】:{}", JSON.toJSON(etOrder)); + return toAjax(orderService.refund(etOrder)); } } diff --git a/eride-common/src/main/java/com/ruoyi/common/constant/ServiceConstants.java b/eride-common/src/main/java/com/ruoyi/common/constant/ServiceConstants.java index 882a7b7..7483a41 100644 --- a/eride-common/src/main/java/com/ruoyi/common/constant/ServiceConstants.java +++ b/eride-common/src/main/java/com/ruoyi/common/constant/ServiceConstants.java @@ -130,14 +130,9 @@ public class ServiceConstants { public static final String PAY_TYPE_WX = "wx"; /** - * 支付方式: sys-系统 免费骑行时,订单金额为0 + * 支付方式: tmwx-太米微信 */ - public static final String PAY_TYPE_SYS = "sys"; - - /** - * 支付方式: alipay-支付宝 - */ - public static final String PAY_TYPE_ALIPAY = "alipay"; + public static final String PAY_TYPE_TMWX = "tmwx"; /** * 支付方式: yj-押金抵扣 @@ -794,5 +789,20 @@ public class ServiceConstants { /**----------------------------是否默认展示设备end----------------------------*/ + /**----------------------------验证码类型start----------------------------*/ + + /** + * 验证码类型: 1-数字验证码 + */ + public static final String CAPTCHA_TYPE_NUMERIC = "1"; + + /** + * 验证码类型: 2-手机验证码 + */ + public static final String CAPTCHA_TYPE_PHONE = "2"; + + /**----------------------------验证码类型end----------------------------*/ + + } diff --git a/eride-common/src/main/java/com/ruoyi/common/enums/PayChannel.java b/eride-common/src/main/java/com/ruoyi/common/enums/PayChannel.java index d0f07fe..a54a2dc 100644 --- a/eride-common/src/main/java/com/ruoyi/common/enums/PayChannel.java +++ b/eride-common/src/main/java/com/ruoyi/common/enums/PayChannel.java @@ -13,7 +13,7 @@ import lombok.Getter; @AllArgsConstructor public enum PayChannel { CT_WX("ctwx", "创特微信支付"), - TL_WX("tlwx", "通联微信支付"); + TM_WX("tmwx", "太米微信支付"); private final String code; diff --git a/eride-common/src/main/java/com/ruoyi/common/pay/tm/Application.java b/eride-common/src/main/java/com/ruoyi/common/pay/tm/Application.java new file mode 100644 index 0000000..76a4e15 --- /dev/null +++ b/eride-common/src/main/java/com/ruoyi/common/pay/tm/Application.java @@ -0,0 +1,96 @@ +package com.ruoyi.common.pay.tm; + +import com.alibaba.fastjson2.JSON; +import com.ruoyi.common.utils.http.HttpUtils; +import com.ruoyi.common.utils.uuid.IdUtils; + +import java.util.HashMap; + +public class Application { + + private final static String HTTP = "https://pos.weixincore.com"; + private final static String SIGNKEY = "ac6d97e67b444b7a43edfc9182634786"; + + public static void main(String[] args) { + orderQuery("tmwx1727172604248"); +// miniPay(); + } + + /** + * 订单查询 + */ + public static void orderQuery(String outTradeId) { + HashMap body = new HashMap<>(); + body.put("outTradeId", outTradeId); + body.put("terminalType", "1"); + body.put("shopId", "488"); + doPost("/open/Pay/orderQuery", body); + } + + /** + * 退款 + */ + public static void refund() { + HashMap body = new HashMap<>(); + body.put("refundFee", "0.01"); + body.put("terminalType", "1"); + body.put("tradeId", "1"); + body.put("shopId", "488"); + doPost("/open/Pay/refund", body); + } + + +// /** +// * jsapi支付 +// */ +// public static void pay() { +// HashMap body = new HashMap(); +// body.put("payAmount", "1"); +// body.put("terminalType", "1"); +// body.put("shopId", "488"); +// // 填充必填字段 +// body.put("payType", "wx_pay"); // 支付方式,可以是 wx.pay, ali.pay, union.online +// body.put("outTradeId", "tradeId123"); // 商户订单号 +// body.put("body", "商品描述"); // 商品描述 +// body.put("notifyUrl", "https://yourdomain.com/notify"); // 异步回调URL +// body.put("frontUrl", "https://yourdomain.com/front"); // 前端页面跳转URL +// doPost("/open/Pay/unifiedOrder", body); +// } + + + /** + * 小程序支付 + */ + public static void miniPay() { + HashMap body = new HashMap<>(); + body.put("payAmount", "1"); + body.put("terminalType", "1"); + body.put("shopId", "488"); + // 填充必填字段 + body.put("payType", "wx_pay"); // 支付方式,可以是 wx.pay, ali.pay, union.online + body.put("outTradeId", IdUtils.getOrderNo("tmwx")); // 商户订单号 + System.out.println("----------------------------------:"+body.get("outTradeId")); + body.put("openid", "o6yEK7Z0OdWM2N_d8ehItn-5NBH8"); // openid + body.put("body", "商品描述"); // 商品描述 + body.put("notifyUrl", "https://yourdomain.com/notify"); // 异步回调URL + body.put("frontUrl", "https://yourdomain.com/front"); // 前端页面跳转URL + doPost("/open/Pay/miniPay", body); + } + + private static void doPost(String url, HashMap body) { + body.put("developerId", "100001"); + body.put("version", "1.0"); + body.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); + body.put("nonceStr", TmPayUtil.getRandomString(16)); + String bodyStr = TmPayUtil.getAsciiSort(body); + String sign = TmPayUtil.getMD5Code(bodyStr+"&key="+SIGNKEY).toUpperCase(); + body.put("sign", sign); + + HashMap headerData = new HashMap(); + headerData.put("Content-Type", "application/json"); + + String response = HttpUtils.sendPostWithHeaders(HTTP + url, headerData,JSON.toJSONString(body)); + System.out.println("API Response: " + response); + } + +} diff --git a/eride-common/src/main/java/com/ruoyi/common/pay/tm/IChannelInfo.java b/eride-common/src/main/java/com/ruoyi/common/pay/tm/IChannelInfo.java new file mode 100644 index 0000000..9cdcaf8 --- /dev/null +++ b/eride-common/src/main/java/com/ruoyi/common/pay/tm/IChannelInfo.java @@ -0,0 +1,16 @@ +package com.ruoyi.common.pay.tm; + +public interface IChannelInfo { + + String getDeveloperId(); + + String getShopId(); + + String getHttpUrl(); + + String getSignKey(); + + String getNotifyUrl(); + + String getSn(); +} diff --git a/eride-common/src/main/java/com/ruoyi/common/pay/tm/TmPayService.java b/eride-common/src/main/java/com/ruoyi/common/pay/tm/TmPayService.java new file mode 100644 index 0000000..2d2743e --- /dev/null +++ b/eride-common/src/main/java/com/ruoyi/common/pay/tm/TmPayService.java @@ -0,0 +1,157 @@ +package com.ruoyi.common.pay.tm; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.pay.tm.vo.RefundInfo; +import com.ruoyi.common.pay.tm.vo.TmTradeInfo; +import com.ruoyi.common.pay.wx.Payable; +import com.ruoyi.common.pay.wx.RefundAble; +import com.ruoyi.common.utils.ServiceUtil; +import com.ruoyi.common.utils.http.HttpUtils; +import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * 太米支付 + */ +@Service +public class TmPayService { + + private final static String SIGNKEY = "b4ixpiogfj5vu3tbkv23gj0dvo2j2ksz"; + private static final Logger log = LoggerFactory.getLogger(TmPayService.class); + + /** + * 订单查询 + */ + public static TmTradeInfo orderQuery(IChannelInfo channel, String outTradeNo) { + HashMap body = new HashMap<>(); + body.put("outTradeId", outTradeNo); + body.put("terminalType", "1"); + body.put("shopId", channel.getShopId()); + String response = doPost(channel.getHttpUrl() + "/open/Pay/orderQuery", body,channel); + if (com.ruoyi.common.utils.StringUtils.hasText(response)) { + JSONObject jsonResponse = JSON.parseObject(response); + if (jsonResponse.getInteger("errCode") == 0 && "ok".equals(jsonResponse.getString("errMsg"))) { + JSONObject tradeInfo = jsonResponse.getJSONObject("tradeInfo"); + return tradeInfo.toJavaObject(TmTradeInfo.class); + } else { + throw new ServiceException("订单查询失败: " + jsonResponse.getString("errMsg")); + } + } + throw new ServiceException("订单查询数据为空"); + } + + /** + * 退款 + */ + public static RefundInfo refund(IChannelInfo channel,RefundAble refundAble) { + HashMap body = new HashMap<>(); + body.put("refundFee", String.valueOf(refundAble.getAmount())); + body.put("terminalType", "1"); + body.put("outTradeId", refundAble.getOutTradeNo()); + body.put("shopId", channel.getShopId()); + String response = doPost(channel.getHttpUrl() + "/open/Pay/refund", body,channel); + if (com.ruoyi.common.utils.StringUtils.hasText(response)) { + JSONObject jsonResponse = JSON.parseObject(response); + if (jsonResponse.getInteger("errCode") == 0 && "退款成功".equals(jsonResponse.getString("errMsg"))) { + JSONObject tradeInfo = jsonResponse.getJSONObject("refundInfo"); + return tradeInfo.toJavaObject(RefundInfo.class); + } else { + throw new ServiceException("退款失败: " + jsonResponse.getString("errMsg")); + } + } + throw new ServiceException("退款数据为空"); + } + + /** + * 关闭订单 + */ + public static void closeOrder(IChannelInfo channel, String outTradeNo) { + HashMap body = new HashMap<>(); + body.put("outTradeId", outTradeNo); + body.put("terminalType", "1"); + body.put("shopId", channel.getShopId()); + String response = doPost(channel.getHttpUrl() + "/open/Pay/orderClose", body, channel); + if (com.ruoyi.common.utils.StringUtils.hasText(response)) { + JSONObject jsonResponse = JSON.parseObject(response); + ServiceUtil.assertion(jsonResponse.getInteger("errCode") != 0,"关闭订单失败: " + jsonResponse.getString("errMsg")); + }else{ + throw new ServiceException("关闭订单数据为空"); + } + } + + /** + * 小程序支付 + */ + public static PrepayWithRequestPaymentResponse pay(IChannelInfo channel, Payable payable) { + HashMap body = new HashMap<>(); + body.put("payAmount", String.valueOf(payable.getAmount())); + body.put("terminalType", "1"); + body.put("shopId", channel.getShopId()); // 从渠道获取shopId + body.put("sn", channel.getSn()); + body.put("payType", "wx_pay"); + body.put("outTradeId", payable.getOutTradeNo()); + body.put("body", payable.getDescription()); + body.put("notifyUrl", channel.getNotifyUrl()); + body.put("openid", payable.getOpenid()); + String response = doPost(channel.getHttpUrl() + "/open/Pay/miniPay", body, channel); + + if (com.ruoyi.common.utils.StringUtils.hasText(response)) { + // 解析 response,提取 "params" 字段 + JSONObject jsonResponse = JSON.parseObject(response); + if (jsonResponse.getInteger("errCode") == 0 && "ok".equals(jsonResponse.getString("errMsg"))) { + // 提取 "params" 并转成 PrepayWithRequestPaymentResponse 对象 + JSONObject params = jsonResponse.getJSONObject("params"); + return params.toJavaObject(PrepayWithRequestPaymentResponse.class); + } else { + throw new ServiceException("支付失败: " + jsonResponse.getString("errMsg")); + } + } + throw new ServiceException("支付数据为空"); + } + + + + private static String doPost(String url, HashMap body, IChannelInfo channel) { + body.put("developerId", channel.getDeveloperId()); + body.put("version", "1.0"); + body.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); + body.put("nonceStr", TmPayUtil.getRandomString(16)); + + String bodyStr = TmPayUtil.getAsciiSort(body); + String sign = TmPayUtil.getMD5Code(bodyStr + "&key=" + channel.getSignKey()).toUpperCase(); + body.put("sign", sign); + + HashMap headerData = new HashMap<>(); + headerData.put("Content-Type", "application/json"); + + String response = HttpUtils.sendPostWithHeaders(url, headerData, JSON.toJSONString(body)); + log.info("doPost请求API响应: {}", response); + return response; + } + + public boolean validSign(Map params) { + // 获取传递过来的签名 + String receivedSign = (String)params.get("sign"); + // 获取签名字段 + System.out.println("获取到的签名-------------:"+receivedSign); + if (receivedSign == null) { + return false; // 如果没有传递签名,验签失败 + } + // 移除签名字段后,重新生成签名 + params.remove("sign"); + // 按照请求时的签名逻辑,生成签名字符串 + String paramsStr = TmPayUtil.getAsciiSort(params); // 按ASCII排序 + String generatedSign = TmPayUtil.getMD5Code(paramsStr + "&key=" + SIGNKEY).toUpperCase(); // 重新生成签名 + System.out.println("新生成的签名-----------:"+generatedSign); + // 比较签名是否一致 + return generatedSign.equals(receivedSign); + } + +} diff --git a/eride-common/src/main/java/com/ruoyi/common/pay/tm/TmPayUtil.java b/eride-common/src/main/java/com/ruoyi/common/pay/tm/TmPayUtil.java new file mode 100644 index 0000000..4f375c6 --- /dev/null +++ b/eride-common/src/main/java/com/ruoyi/common/pay/tm/TmPayUtil.java @@ -0,0 +1,131 @@ +package com.ruoyi.common.pay.tm; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; +import java.util.Map.Entry; + +public class TmPayUtil { + // 全局数组 + private final static String[] strDigits = { "0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; + + private static Random random = null; + + // 返回形式为数字跟字符串 + public static String byteToArrayString(byte bByte) { + int iRet = bByte; + if (iRet < 0) { + iRet += 256; + } + int iD1 = iRet / 16; + int iD2 = iRet % 16; + return strDigits[iD1] + strDigits[iD2]; + } + + // 返回形式只为数字 + public static String byteToNum(byte bByte) { + int iRet = bByte; + if (iRet < 0) { + iRet += 256; + } + return String.valueOf(iRet); + } + + // 转换字节数组为16进制字串 + public static String byteToString(byte[] bByte) { + StringBuffer sBuffer = new StringBuffer(); + for (int i = 0; i < bByte.length; i++) { + sBuffer.append(byteToArrayString(bByte[i])); + } + return sBuffer.toString(); + } + + /** + * md5 加密 + * @param strObj + * @return + */ + public static String getMD5Code(String strObj) { + String resultString = null; + try { + resultString = new String(strObj); + MessageDigest md = MessageDigest.getInstance("MD5"); + // md.digest() 该函数返回值为存放哈希值结果的byte数组 + resultString = byteToString(md.digest(strObj.getBytes())); + } catch (NoSuchAlgorithmException ex) { + ex.printStackTrace(); + } + return resultString; + } + + + + /** + * 获取随机数 + * @param length + * @return + */ + public static String getRandomString(int length) { + // 定义一个字符串(A-Z,a-z1-9)即62位; + String str = "zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890"; + // 由Random生成随机数 + if (random == null) { + random = new Random(); + } + StringBuffer sb = new StringBuffer(); + // 长度为几就循环几次 + for (int i = 0; i < length; ++i) { + // 产生0-61的数字 + int number = random.nextInt(62); + // 将产生的数字通过length次承载到sb中 + sb.append(str.charAt(number)); + } + // 将承载的字符转换成字符串 + return sb.toString(); + } + + public static String getUUID() { + return UUID.randomUUID().toString(); + } + + public static String getUUIDNoLine() { + String s = UUID.randomUUID().toString(); + return s.substring(0, 8) + s.substring(9, 13) + s.substring(14, 18) + s.substring(19, 23) + s.substring(24); + } + + /** + * 参数名ASCII码从小到大排序(字典序) + * @param map + * @return + */ + public static String getAsciiSort(Map map) { + List> infoIds = new ArrayList<>(map.entrySet()); + + // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序) + Collections.sort(infoIds, new Comparator>() { + public int compare(Entry o1, Entry o2) { + return o1.getKey().compareToIgnoreCase(o2.getKey()); + } + }); + + // 构造签名键值对的格式 + StringBuilder sb = new StringBuilder(); + for (Entry item : infoIds) { + String key = item.getKey(); + Object val = item.getValue(); + + if (key != null && !key.isEmpty() && val != null) { + sb.append(key).append("=").append(val.toString()).append("&"); + } + } + + if (sb.length() > 0 && sb.charAt(sb.length() - 1) == '&') { + sb.deleteCharAt(sb.length() - 1); + } + + return sb.toString(); + } + + +} diff --git a/eride-common/src/main/java/com/ruoyi/common/pay/tm/enums/PayStatus.java b/eride-common/src/main/java/com/ruoyi/common/pay/tm/enums/PayStatus.java new file mode 100644 index 0000000..d259fdb --- /dev/null +++ b/eride-common/src/main/java/com/ruoyi/common/pay/tm/enums/PayStatus.java @@ -0,0 +1,63 @@ +package com.ruoyi.common.pay.tm.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 交易结果 + * @author qzz + * 2024/9/24 + */ +@Getter +@AllArgsConstructor +public enum PayStatus { + + SUCCESS("SUCCESS", "支付成功"), + NOTPAY("NOTPAY", "未支付"), + CLOSE("CLOSED", "已关闭"), + REVOKED("REVOKED", "已撤销"), + USERPAYING("USERPAYING", "用户支付中"), + PAYERROR("PAYERROR", "支付失败"), + REFUND("REFUND", "转入退款"), + OPERATE_SUCCESS("OPERATE_SUCCESS", "预授权请求操作成功"), + OPERATE_FAIL("OPERATE_FAIL", "预授权请求操作失败"), + OPERATE_SETTLING("OPERATE_SETTLING", "押金消费已受理"), + REVOKED_SUCCESS("REVOKED_SUCCESS", "预授权请求撤销成功"); + + private final String code; + private final String description; + + /** + * 判断支付状态是否成功 + * @param code 支付状态码 + * @return 是否成功 + */ + public static boolean isSuccess(String code) { + return SUCCESS.getCode().equals(code); + } + + /** + * 判断支付状态是否转入退款 + * @param code 支付状态码 + * @return 是否成功 + */ + public static boolean isRefund(String code) { + return REFUND.getCode().equals(code); + } + + /** + * 根据状态码获取对应的支付状态 + * @param code 支付状态码 + * @return 对应的PayStatus枚举 + */ + public static PayStatus getByCode(String code) { + for (PayStatus status : PayStatus.values()) { + if (status.getCode().equals(code)) { + return status; + } + } + return null; + } +} + + diff --git a/eride-common/src/main/java/com/ruoyi/common/pay/tm/enums/RefundStatus.java b/eride-common/src/main/java/com/ruoyi/common/pay/tm/enums/RefundStatus.java new file mode 100644 index 0000000..49ab6b1 --- /dev/null +++ b/eride-common/src/main/java/com/ruoyi/common/pay/tm/enums/RefundStatus.java @@ -0,0 +1,42 @@ +package com.ruoyi.common.pay.tm.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 退款状态枚举 + * @author + * 2024/09/24 + */ +@Getter +@AllArgsConstructor +public enum RefundStatus { + FAILED(0, "退款失败"), + REFUNDED(1, "转入退款"); + + private final int code; + private final String description; + + /** + * 根据状态码判断是否退款成功 + * @param code 状态码 + * @return 是否退款成功 + */ + public static boolean isSuccess(int code) { + return REFUNDED.getCode() == code; + } + + /** + * 根据状态码获取对应的退款状态枚举 + * @param code 状态码 + * @return 对应的 RefundStatus 枚举 + */ + public static RefundStatus getByCode(int code) { + for (RefundStatus status : RefundStatus.values()) { + if (status.getCode() == code) { + return status; + } + } + return null; + } +} diff --git a/eride-common/src/main/java/com/ruoyi/common/pay/tm/vo/RefundInfo.java b/eride-common/src/main/java/com/ruoyi/common/pay/tm/vo/RefundInfo.java new file mode 100644 index 0000000..e0abca5 --- /dev/null +++ b/eride-common/src/main/java/com/ruoyi/common/pay/tm/vo/RefundInfo.java @@ -0,0 +1,29 @@ +package com.ruoyi.common.pay.tm.vo; + +import com.ruoyi.common.pay.tm.enums.RefundStatus; +import lombok.Data; + +/** + * 退款信息对象 + * @author + * 2024/09/24 + */ +@Data +public class RefundInfo { + private String id; // 太米系统退款记录Id + private Long tradeInfoId; // 太米系统流水Id + private String module; // 模块: pay, mall, recharge, become_member, eatIn, takeOut, selfTake, payment_card, times_card + private String remark; // 备注 + private Long merchantId; // 品牌Id + private String shopId; // 门店Id + private Long merchantUserId; // 门店员工Id + private Long codeId; // 款台码Id + private Long memberInfoId; // 会员Id + private Long workRecordId; // 交班记录Id + private String fromType; // 订单来源: wx, alipay, web, mini, pos, pc, desktop, api + private String refundTime; // 退款成功时间 + private String refundMessage; // 退款失败原因 + private RefundStatus refundStatus; // 退款状态: RefundStatus 枚举 + private String refundAmount; // 已退款金额 + private String createTime; // 创建时间 +} diff --git a/eride-common/src/main/java/com/ruoyi/common/pay/tm/vo/TmTradeInfo.java b/eride-common/src/main/java/com/ruoyi/common/pay/tm/vo/TmTradeInfo.java new file mode 100644 index 0000000..d6a1fbd --- /dev/null +++ b/eride-common/src/main/java/com/ruoyi/common/pay/tm/vo/TmTradeInfo.java @@ -0,0 +1,181 @@ +package com.ruoyi.common.pay.tm.vo; + +import com.ruoyi.common.pay.tm.enums.PayStatus; +import lombok.Data; + +@Data +public class TmTradeInfo { + + /** + * 太米系统流水Id + */ + private Integer id; + + /** + * 第三方内部流水号 + */ + private String outTradeId; + + /** + * 微信或支付宝或银联的订单号。个别支付渠道可能无此参数 + */ + private String transactionId; + + /** + * 太米商户订单号 + */ + private String orderNum; + + /** + * 支付凭证条码,个别支付渠道可能返回空 + */ + private String barCode; + + /** + * 模块:pay:收银;mall:优选卡券货架;recharge:充值; + * become_member:会员购买;eatIn:店内下单; + * takeOut:外送订单;selfTake:预约自取; + * payment_card:付费卡券;times_card:次/月卡 + */ + private String module; + + /** + * 备注 + */ + private String remark; + + /** + * 品牌Id + */ + private Integer merchantId; + + /** + * 门店Id + */ + private Integer shopId; + + /** + * 门店员工id + */ + private Integer merchantUserId; + + /** + * 款台码Id + */ + private Integer codeId; + + /** + * 会员Id + */ + private Integer memberInfoId; + + /** + * 交班记录id + */ + private Integer workRecordId; + + /** + * 订单来源:wx:微信收款码;alipay:支付宝收款码; + * web:Web页面;mini:小程序;pos:POS机; + * pc:PC;desktop:台式消费机;api:开放平台接口 + */ + private String fromType; + + /** + * 订单总额,单位分 + */ + private Integer orderAmount; + + /** + * 会员优惠,单位分 + */ + private Integer memberCoupon; + + /** + * 活动优惠,单位分 + */ + private Integer activityCoupon; + + /** + * 卡券优惠,单位分 + */ + private Integer cardCoupon; + + /** + * 积分抵扣,单位分 + */ + private Integer pointDeduction; + + /** + * 实收金额,单位分 + */ + private Integer incomeAmount; + + /** + * 支付方式:wx_pay:微信支付;ali_pay:支付宝; + * union_offline:银行卡;union_qrcode:银联扫码; + * union_online:银联钱包;member_wallet:会员钱包;cash:现金 + */ + private String payType; + + /** + * 1、已支付 0、未支付 + */ + private Integer isPaid; + + /** + * 支付状态: + * SUCCESS:支付成功;NOTPAY:未支付;CLOSE:已关闭; + * REVOKED:已撤销;USERPAYING:用户支付中; + * PAYERROR:支付失败;REFUND:转入退款; + * OPERATE_SUCCESS:预授权请求操作成功、OPERATE_FAIL:预授权请求操作失败; + * OPERATE_SETTLING:押金消费已受理; + * REVOKED_SUCCESS:预授权请求撤销成功 + */ + private PayStatus payStatus; + + /** + * 支付时间 + */ + private String payTime; + + /** + * 支付失败原因 + */ + private String payError; + + /** + * 退款状态:0表示未退款,1表示转入退款 + */ + private Integer refundStatus; + + /** + * 已退款金额,单位分 + */ + private String refundAmount; + + /** + * 终端sn号 + */ + private String sn; + + /** + * 应结订单金额(微信代金券用) + */ + private String settlementTotalFee; + + /** + * 0 : 普通订单 1:刷脸设备刷脸支付 2 : 刷脸设备扫码支付 3 : 刷脸设备会员钱包支付 + */ + private String isFromFacePay; + + /** + * 总代金券金额(微信代金券用) + */ + private String couponFee; + + /** + * 创建时间 + */ + private String createTime; +} diff --git a/eride-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java b/eride-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java index c3d5d15..c2330a6 100644 --- a/eride-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java +++ b/eride-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java @@ -284,6 +284,65 @@ public class HttpUtils } } + /** + * 向指定 URL 发送 POST 方法的请求,并支持自定义请求头和 JSON 请求体 + * + * @param url 发送请求的 URL + * @param headerData 请求头信息,键值对形式 + * @param body 请求体,通常为 JSON 格式的字符串 + * @return 所代表远程资源的响应结果 + */ + public static String sendPostWithHeaders(String url, Map headerData, String body) { + log.info("body------- - {}", body); + PrintWriter out = null; + BufferedReader in = null; + StringBuilder result = new StringBuilder(); + try { + log.info("sendPostWithHeaders - {}", url); + URL realUrl = new URL(url); + URLConnection conn = realUrl.openConnection(); + + // 设置请求头信息 + for (Map.Entry entry : headerData.entrySet()) { + conn.setRequestProperty(entry.getKey(), entry.getValue()); + } + conn.setDoOutput(true); + conn.setDoInput(true); + // 发送 POST 请求体数据 + out = new PrintWriter(conn.getOutputStream()); + out.print(body); // 发送 JSON 格式的 body + out.flush(); + + // 读取响应数据 + in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8)); + String line; + while ((line = in.readLine()) != null) { + result.append(line); + } + log.info("recv - {}", result); + } catch (ConnectException e) { + log.error("调用HttpUtils.sendPostWithHeaders ConnectException, url={}, body={}", url, body, e); + } catch (SocketTimeoutException e) { + log.error("调用HttpUtils.sendPostWithHeaders SocketTimeoutException, url={}, body={}", url, body, e); + } catch (IOException e) { + log.error("调用HttpUtils.sendPostWithHeaders IOException, url={}, body={}", url, body, e); + } catch (Exception e) { + log.error("调用HttpUtils.sendPostWithHeaders Exception, url={}, body={}", url, body, e); + } finally { + try { + if (out != null) { + out.close(); + } + if (in != null) { + in.close(); + } + } catch (IOException ex) { + log.error("调用in.close Exception, url={}, body={}", url, body, ex); + } + } + return result.toString(); + } + /** * 向指定 URL 发送POST方法的请求 * diff --git a/eride-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java b/eride-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java index 3606820..46618c2 100644 --- a/eride-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java +++ b/eride-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java @@ -47,6 +47,9 @@ import com.ruoyi.system.service.ISysConfigService; import java.util.List; +import static com.ruoyi.common.constant.ServiceConstants.CAPTCHA_TYPE_NUMERIC; +import static com.ruoyi.common.constant.ServiceConstants.CAPTCHA_TYPE_PHONE; + /** * 登录校验方法 * @@ -96,7 +99,7 @@ public class SysLoginService { if("1".equals(type)){ // 验证码校验 - validateCaptcha(username, code, uuid); + validateCaptcha(username, code, uuid,CAPTCHA_TYPE_NUMERIC); } // 登录前置校验 loginPreCheck(username, password); @@ -181,9 +184,10 @@ public class SysLoginService * @param username 用户名 * @param code 验证码 * @param uuid 唯一标识 + * @param type 验证码类型:1-数字验证码;2-手机验证码 * @return 结果 */ - public void validateCaptcha(String username, String code, String uuid) + public void validateCaptcha(String username, String code, String uuid, String type) { boolean captchaEnabled = configService.selectCaptchaEnabled(); if (captchaEnabled) @@ -195,7 +199,9 @@ public class SysLoginService AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"))); throw new CaptchaExpireException(); } - redisCache.deleteObject(verifyKey); + if(type.equals(CAPTCHA_TYPE_NUMERIC)){ + redisCache.deleteObject(verifyKey); + } if (!code.equalsIgnoreCase(captcha)) { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); @@ -419,7 +425,7 @@ public class SysLoginService loginPreCheck(username, password); }else{ if(!"8888".equals(code)){ - validateCaptcha(username, code, uuid); //校验验证码 + validateCaptcha(username, code, uuid, CAPTCHA_TYPE_PHONE); //校验验证码 } } Authentication authentication = null; // 用户验证 @@ -462,8 +468,7 @@ public class SysLoginService */ public int forgetAppPwd(LoginBody loginBody) { EUser user = eUserService.selectUserByPhone(loginBody.getPhone()); - validateCaptcha(loginBody.getPhone(), loginBody.getPhoneCode(), loginBody.getUuid()); //校验验证码 - int i = eUserService.updateUserPwd(user.getUserId(), SecurityUtils.encryptPassword(loginBody.getNewPassword())); - return i; + validateCaptcha(loginBody.getPhone(), loginBody.getPhoneCode(), loginBody.getUuid(),CAPTCHA_TYPE_PHONE); //校验验证码 + return eUserService.updateUserPwd(user.getUserId(), SecurityUtils.encryptPassword(loginBody.getNewPassword())); } } diff --git a/eride-system/src/main/java/com/ruoyi/e/order/domain/order/EOrder.java b/eride-system/src/main/java/com/ruoyi/e/order/domain/order/EOrder.java index 7bf437b..ae11121 100644 --- a/eride-system/src/main/java/com/ruoyi/e/order/domain/order/EOrder.java +++ b/eride-system/src/main/java/com/ruoyi/e/order/domain/order/EOrder.java @@ -135,12 +135,6 @@ public class EOrder extends BaseEntity { @Excel(name = "调度费") private BigDecimal dispatchFee; - /** - * 配送费 - */ - @Excel(name = "配送费") - private BigDecimal deliveryFee; - /** * 租赁费 */ @@ -190,33 +184,12 @@ public class EOrder extends BaseEntity { @Excel(name = "是否押金抵扣") private String depositDeduction; - /** - * 押金订单号,押金抵扣时,记录是哪个押金订单 - */ - private String depositOrderNo; - /** * 扣除金额 */ @Excel(name = "扣除金额") private BigDecimal deductionAmount; - /** - * 使用过的sn - */ - private String usedSn; - - /** - * 换车原因 - */ - private String changeReason; - - /** - * 还车结算___小时后自动退押金 - */ - @Excel(name = "还车结算___小时后自动退押金") - private Integer autoRefundDeposit; - /** * 租赁单位 */ @@ -253,12 +226,6 @@ public class EOrder extends BaseEntity { @Excel(name = "支付渠道名称") private String channelName; - /** - * 配送方式 - */ - @Excel(name = "配送方式") - private Integer deliveryMethod; - /** * 取车时间 */ @@ -361,11 +328,6 @@ public class EOrder extends BaseEntity { */ private String returnType; - /** - * 还车方式:1-自行前往门店;2-上门取车 - */ - private String returnMethod; - /** * 还车地址 */ diff --git a/eride-system/src/main/java/com/ruoyi/e/order/service/IEOrderService.java b/eride-system/src/main/java/com/ruoyi/e/order/service/IEOrderService.java index 04e1d69..858d746 100644 --- a/eride-system/src/main/java/com/ruoyi/e/order/service/IEOrderService.java +++ b/eride-system/src/main/java/com/ruoyi/e/order/service/IEOrderService.java @@ -174,8 +174,7 @@ public interface IEOrderService public ERefund createRefund(String reason, Long userId, String orderNo, BigDecimal refundAmount, BigDecimal dispatchFee, - BigDecimal deliveryFee, - BigDecimal leaseFee, String outRefundNo, String type); + BigDecimal leaseFee, BigDecimal deposit, String outRefundNo, String type); diff --git a/eride-system/src/main/java/com/ruoyi/e/order/service/impl/EOrderConverterImpl.java b/eride-system/src/main/java/com/ruoyi/e/order/service/impl/EOrderConverterImpl.java index 379fb9f..c324f03 100644 --- a/eride-system/src/main/java/com/ruoyi/e/order/service/impl/EOrderConverterImpl.java +++ b/eride-system/src/main/java/com/ruoyi/e/order/service/impl/EOrderConverterImpl.java @@ -1,5 +1,6 @@ package com.ruoyi.e.order.service.impl; +import cn.hutool.core.util.ObjectUtil; import com.ruoyi.common.constant.ServiceConstants; import com.ruoyi.common.core.domain.entity.EUserVO; import com.ruoyi.common.utils.SecurityUtils; @@ -54,10 +55,12 @@ public class EOrderConverterImpl implements IEOrderConverter { // 车型 EModelVO model = modelService.selectEModelByModelId(eDevice.getModelId()); ServiceUtil.assertion(model == null, "设备【"+order.getSn()+"】的车型不存在"); + ServiceUtil.assertion(eDevice.getUserId() == null, "设备【"+order.getSn()+"】的商户不存在"); + // 商户 EUserVO merchantVO = userService.selectUserById(eDevice.getUserId()); - ServiceUtil.assertion(merchantVO == null, "商户不存在"); + ServiceUtil.assertion(ObjectUtil.isNull(merchantVO), "商户不存在"); ServiceUtil.assertion(merchantVO.getServiceFeeProportion() == null, "商户【"+merchantVO.getUserName()+"】的平台服务费未配置"); ServiceUtil.assertion(merchantVO.getPayChannel() == null, "商户【"+merchantVO.getUserName()+"】的支付渠道未配置"); diff --git a/eride-system/src/main/java/com/ruoyi/e/order/service/impl/EOrderServiceImpl.java b/eride-system/src/main/java/com/ruoyi/e/order/service/impl/EOrderServiceImpl.java index 65b92e6..2386f6b 100644 --- a/eride-system/src/main/java/com/ruoyi/e/order/service/impl/EOrderServiceImpl.java +++ b/eride-system/src/main/java/com/ruoyi/e/order/service/impl/EOrderServiceImpl.java @@ -233,12 +233,12 @@ public class EOrderServiceImpl implements IEOrderService ERefundVO refundVO = refundService.getRefundedAmount(orderNo); BigDecimal refundableAmount = order.getPayFee().subtract(refundVO.getTotalRefundAmount()); BigDecimal refundableDispatchFee = order.getDispatchFee().subtract(refundVO.getTotalDispatchFee()); - BigDecimal refundableDeliveryFee = order.getDeliveryFee().subtract(refundVO.getTotalDeliveryFee()); +// BigDecimal refundableDeliveryFee = order.getDeliveryFee().subtract(refundVO.getTotalDeliveryFee()); BigDecimal refundableDeposit = order.getDeposit().subtract(refundVO.getTotalDeposit()); BigDecimal refundableLeaseFee = order.getLeaseFee().subtract(refundVO.getTotalLeaseFee()); order.setRefundableTotalAmount(refundableAmount); order.setRefundableDispatchFee(refundableDispatchFee); - order.setRefundableDeliveryFee(refundableDeliveryFee); +// order.setRefundableDeliveryFee(refundableDeliveryFee); order.setRefundableDeposit(refundableDeposit); order.setRefundableLeaseFee(refundableLeaseFee); } @@ -801,50 +801,43 @@ public class EOrderServiceImpl implements IEOrderService @Override public Boolean merchantReturn(String orderNo) { EOrderVO order = orderMapper.selectRlOrderByOrderNo(orderNo); - if(ObjectUtil.isNull(order)){ - throw new ServiceException("订单不存在"); - } - BigDecimal deposit = order.getDeposit(); - BigDecimal overdueFee = order.getOverdueFee(); - BigDecimal deductionAmount = order.getDeductionAmount(); - BigDecimal remainingDeposit = deposit.subtract(overdueFee).subtract(deductionAmount); - if(!ServiceConstants.ORDER_PAY_STATUS_PAID.equals(order.getPaid())){ - throw new ServiceException("订单未支付,不能还车", HttpStatus.ERROR); - } - if(!(ServiceConstants.ORDER_STATUS_TO_BE_AUDITED.equals(order.getStatus()) || ServiceConstants.ORDER_STATUS_IN_USE.equals(order.getStatus()))){ - throw new ServiceException("订单非待审核或骑行中状态,不能还车", HttpStatus.ERROR); - } + ServiceUtil.assertion(ObjectUtil.isNull(order),"订单不存在"); + ServiceUtil.assertion(!ServiceConstants.ORDER_PAY_STATUS_PAID.equals(order.getPaid()),"订单未支付,不能还车", HttpStatus.ERROR); + ServiceUtil.assertion(!(ServiceConstants.ORDER_STATUS_TO_BE_AUDITED.equals(order.getStatus()) || + ServiceConstants.ORDER_STATUS_IN_USE.equals(order.getStatus())),"订单非待审核或骑行中状态,不能还车"); + Boolean execute = transactionTemplate.execute(e -> { - /** 1.更新订单信息*/ + ServiceUtil.assertion(ObjectUtil.isNull(order.getOverdueFee()),"逾期费为null"); + ServiceUtil.assertion(ObjectUtil.isNull(order.getDeductionAmount()),"车损扣款为null"); + BigDecimal remainingDeposit = order.getDeposit().subtract(order.getOverdueFee()).subtract(order.getDeductionAmount());// 剩余可退押金 = 押金 - 逾期费 - 车损扣款 + /* 1.更新订单信息*/ updateOrderStatus(orderNo); - /** 2.更新车辆状态*/ + /* 2.更新车辆状态*/ updateDeviceInfo(order.getSn()); - /** 3.记录订单履历*/ + /* 3.记录订单履历*/ if(!orderOperService.recordOrderHistory(orderNo,ServiceConstants.ORDER_OPERATION_RETURN_END, order.getStatus(),order.getStatus(),order.getPayFee(),order.getPayFee(),order.getUserId(),order.getPhone(),"已退款:-"+remainingDeposit+"元")){ throw new ServiceException("【记录订单履历失败】"); } if(remainingDeposit.compareTo(BigDecimal.ZERO) > 0){ - /** 4.执行退还剩余押金操作*/ - /** 5.新增一条退款记录*/ + /* 4.执行退还剩余押金操作*/ + /* 5.新增一条退款记录*/ String outRefundNo = saveDepositRefundObj(order, remainingDeposit); - logger.info("【商家还车】退还剩余押金:"+remainingDeposit); + logger.info("【商家还车】退还剩余押金:{}", remainingDeposit); wxPayService.refund(order, "审核后退押金",remainingDeposit,outRefundNo); } return Boolean.TRUE; }); - if(!execute)throw new ServiceException("商家还车失败"); + if(Boolean.FALSE.equals(execute))throw new ServiceException("商家还车失败"); return true; } @NotNull private String saveDepositRefundObj(EOrderVO rlOrderVO, BigDecimal refundAmount) { String outRefundNo = IdUtils.getOrderNo("ref"); - ERefund refund1= createRefund("押金退款", rlOrderVO.getUserId(), rlOrderVO.getOrderNo(), refundAmount, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, outRefundNo,ServiceConstants.REFUND_TYPE_DEPOSIT); + ERefund refund1= createRefund("押金退款", rlOrderVO.getUserId(), rlOrderVO.getOrderNo(), refundAmount, BigDecimal.ZERO, BigDecimal.ZERO, refundAmount, outRefundNo,ServiceConstants.REFUND_TYPE_DEPOSIT); int refundResult = refundService.insertEtRefund(refund1); - if(refundResult>0){ - logger.info("保存退款对象成功"); - } + ServiceUtil.assertion(refundResult == 0,"保存退款对象失败"); logger.info("总押金:【{}】,退款金额:【{}】", rlOrderVO.getDeposit(), refundAmount); return outRefundNo; } @@ -887,42 +880,27 @@ public class EOrderServiceImpl implements IEOrderService //根据订单号查询订单信息 /** 1. 校验 */ EOrderVO rlOrderVO = orderMapper.selectRlOrderByOrderNo(etOrder.getOrderNo()); - refundVerify(rlOrderVO); + BigDecimal refundAmount = refundPrefixVerify(etOrder,rlOrderVO); /** 2.计算出退款的比例 保留两位小数点 比如退款金额为5元, 订单金额为32元 退款比例 = 5/32 = 0.16 (四舍五入)由系统来平账*/ //退款金额 调度费(商家取车) 配送费(送车上门) 租赁费 - BigDecimal refundAmount = new BigDecimal("0"); - BigDecimal dispatchFee = etOrder.getDispatchFee(); - if(ObjectUtil.isNotNull(dispatchFee) && !dispatchFee.equals(BigDecimal.ZERO)){ - refundAmount = refundAmount.add(dispatchFee); - } - BigDecimal deliveryFee = etOrder.getDeliveryFee(); - if(ObjectUtil.isNotNull(deliveryFee) && !deliveryFee.equals(BigDecimal.ZERO)){ - refundAmount = refundAmount.add(deliveryFee); - } - BigDecimal leaseFee = etOrder.getLeaseFee(); - if(ObjectUtil.isNotNull(leaseFee) && !leaseFee.equals(BigDecimal.ZERO)){ - refundAmount = refundAmount.add(leaseFee); - } - BigDecimal deposit = etOrder.getDeposit(); - if(ObjectUtil.isNotNull(deposit) && !deposit.equals(BigDecimal.ZERO)){ - refundAmount = refundAmount.add(deposit); - } - if(refundAmount.compareTo(BigDecimal.ZERO) == 0){ - throw new ServiceException("总退款金额不能为0"); - } + BigDecimal refundPercentage = refundAmount.divide(rlOrderVO.getPayFee(), 2, RoundingMode.HALF_UP); - BigDecimal finalRefundAmount = refundAmount; Boolean execute = transactionTemplate.execute(e -> { - /** 3. 根据分成列表,遍历用户,新增账变 */ + /** todo 3. 根据分成列表,退还相应比例服务费v */ // refundDividendHandle(rlOrderVO, refundPercentage); /** 4.记录退款表 创建退款对象*/ - String outRefundNo = saveRefundObj(rlOrderVO, finalRefundAmount, dispatchFee, deliveryFee, leaseFee); + String outRefundNo = saveRefundObj(rlOrderVO, refundAmount, etOrder.getDispatchFee(), etOrder.getLeaseFee(), rlOrderVO.getDeposit()); if(!orderOperService.recordOrderHistory(rlOrderVO.getOrderNo(),ServiceConstants.ORDER_OPERATION_REFUND, - rlOrderVO.getStatus(),rlOrderVO.getStatus(),rlOrderVO.getPayFee(),rlOrderVO.getPayFee(),rlOrderVO.getUserId(),rlOrderVO.getPhone(),"已退款: "+finalRefundAmount+"元")){ + rlOrderVO.getStatus(),rlOrderVO.getStatus(),rlOrderVO.getPayFee(),rlOrderVO.getPayFee(),rlOrderVO.getUserId(),rlOrderVO.getPhone(),"已退款: "+ refundAmount +"元")){ throw new ServiceException("【退款】更新订单信息失败"); } /** 5. 发起退款 */ - wxPayService.refund(rlOrderVO, "商家退款金额", finalRefundAmount,outRefundNo); + try { + wxPayService.refund(rlOrderVO, "商家退款金额", refundAmount,outRefundNo); + }catch (com.wechat.pay.java.core.exception.ServiceException ex){ + logger.error("退款失败:{}",ex.getErrorMessage()); + throw new ServiceException("退款失败:"+ex.getErrorMessage()); + } return Boolean.TRUE; }); if(Boolean.FALSE.equals(execute))throw new ServiceException("【订单退款】失败"); @@ -930,13 +908,11 @@ public class EOrderServiceImpl implements IEOrderService } @NotNull - private String saveRefundObj(EOrderVO rlOrderVO, BigDecimal refundAmount, BigDecimal dispatchFee, BigDecimal deliveryFee, BigDecimal leaseFee) { + private String saveRefundObj(EOrderVO rlOrderVO, BigDecimal refundAmount, BigDecimal dispatchFee, BigDecimal leaseFee, BigDecimal deposit) { String outRefundNo = IdUtils.getOrderNo("ref"); - ERefund refund1= createRefund("商家退款金额", rlOrderVO.getUserId(), rlOrderVO.getOrderNo(), refundAmount, dispatchFee, deliveryFee, leaseFee, outRefundNo,ServiceConstants.REFUND_TYPE_SYSTEM); + ERefund refund1= createRefund("商家退款金额", rlOrderVO.getUserId(), rlOrderVO.getOrderNo(), refundAmount, dispatchFee, leaseFee, deposit, outRefundNo,ServiceConstants.REFUND_TYPE_SYSTEM); int refundResult = refundService.insertEtRefund(refund1); - if(refundResult>0){ - logger.info("保存退款对象成功"); - } + ServiceUtil.assertion(refundResult == 0,"保存退款对象失败"); logger.info("总金额:【{}】,退款金额:【{}】", rlOrderVO.getTotalFee(), refundAmount); return outRefundNo; } @@ -963,46 +939,55 @@ public class EOrderServiceImpl implements IEOrderService // } // } - /** 退款校验*/ - private void refundVerify(EOrderVO rlOrderVO) { - if(ObjectUtil.isNull(rlOrderVO)){ - throw new ServiceException("订单不存在"); + /** 退款校验 */ + private BigDecimal refundPrefixVerify(EOrderQuery query,EOrderVO vo) { + ServiceUtil.assertion(ObjectUtil.isNull(vo), "订单不存在"); + ServiceUtil.assertion(!ServiceConstants.ORDER_STATUS_ORDER_END.equals(vo.getStatus()), "退款失败,订单未结束"); + ServiceUtil.assertion(ServiceConstants.ORDER_PAY_STATUS_NON_PAYMENT.equals(vo.getPaid()), "订单未支付,不能退款"); + + BigDecimal refundAmount = BigDecimal.ZERO; + BigDecimal dispatchFee = query.getDispatchFee(); + if(ObjectUtil.isNotNull(dispatchFee) && !dispatchFee.equals(BigDecimal.ZERO)){ + refundAmount = refundAmount.add(dispatchFee); } - if (!ServiceConstants.ORDER_STATUS_ORDER_END.equals(rlOrderVO.getStatus())) { - throw new ServiceException("退款失败,订单未结束"); + BigDecimal leaseFee = query.getLeaseFee(); + if(ObjectUtil.isNotNull(leaseFee) && !leaseFee.equals(BigDecimal.ZERO)){ + refundAmount = refundAmount.add(leaseFee); } - if(ServiceConstants.ORDER_PAY_STATUS_NON_PAYMENT.equals(rlOrderVO.getPaid())){ - throw new ServiceException("订单未支付,不能退款"); + BigDecimal deposit = query.getDeposit(); + if(ObjectUtil.isNotNull(deposit) && !deposit.equals(BigDecimal.ZERO)){ + refundAmount = refundAmount.add(deposit); } + + ServiceUtil.assertion(refundAmount.compareTo(BigDecimal.ZERO) == 0, "总退款金额不能为0"); + ServiceUtil.assertion(refundAmount.compareTo(vo.getPayFee()) > 0, "总退款金额不能大于订单金额"); + + return refundAmount; } @Override - public ERefund createRefund(String reason, Long userId, String orderNo, BigDecimal refundAmount, BigDecimal dispatchFee, BigDecimal deliveryFee, BigDecimal leaseFee, String outRefundNo, String type) { + public ERefund createRefund(String reason, Long userId, String orderNo, BigDecimal refundAmount, BigDecimal dispatchFee, BigDecimal leaseFee, BigDecimal deposit, String outRefundNo, String type) { ERefund etRefund = new ERefund(); etRefund.setAmount(refundAmount); etRefund.setReason(reason); etRefund.setDispatchFee(dispatchFee); - etRefund.setDeliveryFee(deliveryFee); + etRefund.setDeposit(deposit); etRefund.setLeaseFee(leaseFee); etRefund.setOrderNo(orderNo); etRefund.setUserId(userId); etRefund.setRefundNo(outRefundNo); etRefund.setType(type); - if(type.equals(ServiceConstants.REFUND_TYPE_DEPOSIT)){ - etRefund.setItemDesc("押金退款"); - }else{ - StringBuilder itemDesc = new StringBuilder(); - if(ObjectUtil.isNotNull(deliveryFee) && !deliveryFee.equals(BigDecimal.ZERO)){ - itemDesc.append("配送费:").append(deliveryFee).append("元,"); - } - if(ObjectUtil.isNotNull(dispatchFee) && !dispatchFee.equals(BigDecimal.ZERO)){ - itemDesc.append("调度费:").append(dispatchFee).append("元,"); - } - if(ObjectUtil.isNotNull(leaseFee) && !leaseFee.equals(BigDecimal.ZERO)){ - itemDesc.append("租赁费:").append(leaseFee).append("元,"); - } - etRefund.setItemDesc(itemDesc.toString()); + StringBuilder itemDesc = new StringBuilder(); + if(ObjectUtil.isNotNull(deposit) && !deposit.equals(BigDecimal.ZERO)){ + itemDesc.append("押金:").append(deposit).append("元,"); } + if(ObjectUtil.isNotNull(dispatchFee) && !dispatchFee.equals(BigDecimal.ZERO)){ + itemDesc.append("调度费:").append(dispatchFee).append("元,"); + } + if(ObjectUtil.isNotNull(leaseFee) && !leaseFee.equals(BigDecimal.ZERO)){ + itemDesc.append("租赁费:").append(leaseFee).append("元,"); + } + etRefund.setItemDesc(itemDesc.toString()); return etRefund; } diff --git a/eride-system/src/main/java/com/ruoyi/system/domain/channel/Channel.java b/eride-system/src/main/java/com/ruoyi/system/domain/channel/Channel.java index 3fc7c2f..bf51d42 100644 --- a/eride-system/src/main/java/com/ruoyi/system/domain/channel/Channel.java +++ b/eride-system/src/main/java/com/ruoyi/system/domain/channel/Channel.java @@ -64,4 +64,16 @@ public class Channel extends BaseEntity /** appid */ private String appid; + private String developerId; + + /** 门店Id */ + private String shopId; + + private String httpUrl; + + private String signKey; + + /** 终端sn */ + private String sn; + } diff --git a/eride-system/src/main/java/com/ruoyi/system/domain/channel/ChannelVO.java b/eride-system/src/main/java/com/ruoyi/system/domain/channel/ChannelVO.java index 8750f14..cfd1bc4 100644 --- a/eride-system/src/main/java/com/ruoyi/system/domain/channel/ChannelVO.java +++ b/eride-system/src/main/java/com/ruoyi/system/domain/channel/ChannelVO.java @@ -1,5 +1,6 @@ package com.ruoyi.system.domain.channel; +import com.ruoyi.common.pay.tm.IChannelInfo; import lombok.Data; /** @@ -7,5 +8,5 @@ import lombok.Data; * 2024/7/28 */ @Data -public class ChannelVO extends Channel { +public class ChannelVO extends Channel implements IChannelInfo { } diff --git a/eride-system/src/main/java/com/ruoyi/system/domain/refund/ERefund.java b/eride-system/src/main/java/com/ruoyi/system/domain/refund/ERefund.java index 4bb3c4c..8eef265 100644 --- a/eride-system/src/main/java/com/ruoyi/system/domain/refund/ERefund.java +++ b/eride-system/src/main/java/com/ruoyi/system/domain/refund/ERefund.java @@ -51,8 +51,8 @@ public class ERefund extends BaseEntity /** 调度费 */ private BigDecimal dispatchFee; - /** 配送费 */ - private BigDecimal deliveryFee; +// /** 配送费 */ +// private BigDecimal deliveryFee; /** 租赁费 */ private BigDecimal leaseFee; diff --git a/eride-system/src/main/java/com/ruoyi/system/service/IEDeviceService.java b/eride-system/src/main/java/com/ruoyi/system/service/IEDeviceService.java index d19043a..bdccf45 100644 --- a/eride-system/src/main/java/com/ruoyi/system/service/IEDeviceService.java +++ b/eride-system/src/main/java/com/ruoyi/system/service/IEDeviceService.java @@ -43,7 +43,7 @@ public interface IEDeviceService extends IService * @param sn 设备主键 * @return 设备 */ - public EDevice selectEDeviceBySn(String sn); + public EDeviceVO selectEDeviceBySn(String sn); /** * 查询设备列表 diff --git a/eride-system/src/main/java/com/ruoyi/system/service/IWxPayService.java b/eride-system/src/main/java/com/ruoyi/system/service/IWxPayService.java index 6f457bc..c158ddc 100644 --- a/eride-system/src/main/java/com/ruoyi/system/service/IWxPayService.java +++ b/eride-system/src/main/java/com/ruoyi/system/service/IWxPayService.java @@ -52,17 +52,6 @@ public interface IWxPayService { */ void refund(EOrder etOrder, String reason, BigDecimal amount, String outRefundNo); -// /** -// * 发起商家转账 -// * @param sysDept 运营商对象 -// * @param batchNo 批次号 -// * @param batchName 批次名称 -// * @param batchRemark 转账说明 -// * @param totalAmount 转账总金额 -// * @param totalNum 转账总笔数 -// * @param transferDetailInputs 转账明细列表 -// */ -// InitiateBatchTransferResponse transfer(SysDept sysDept,String batchNo,String batchName,String batchRemark,BigDecimal totalAmount,Integer totalNum,List transferDetailInputs); /** * 根据退款单号查询退款信息 diff --git a/eride-system/src/main/java/com/ruoyi/system/service/impl/EDeviceServiceImpl.java b/eride-system/src/main/java/com/ruoyi/system/service/impl/EDeviceServiceImpl.java index 19a9809..0c61481 100644 --- a/eride-system/src/main/java/com/ruoyi/system/service/impl/EDeviceServiceImpl.java +++ b/eride-system/src/main/java/com/ruoyi/system/service/impl/EDeviceServiceImpl.java @@ -190,8 +190,8 @@ public class EDeviceServiceImpl extends ServiceImpl impl */ @SneakyThrows @Override - public EDevice selectEDeviceBySn(String sn) { - return deviceMapper.selectEDeviceBySn(sn); + public EDeviceVO selectEDeviceBySn(String sn) { + return getLatestLocationBySn(sn); } /** @@ -218,31 +218,7 @@ public class EDeviceServiceImpl extends ServiceImpl impl if (ObjectUtil.isNull(rlDevice)) { throw new ServiceException("设备不存在:"+ sn); } - String msg = redisCache.getCacheObject(CacheConstants.CACHE_DEVICE_KEY + rlDevice.getSn()); - if(StrUtil.isNotBlank(msg)){ - log.info("【根据sn号查询车辆实时信息】-========redis缓存中的数据:" + msg); - LogEntry logEntry = JSONObject.parseObject(msg, LogEntry.class); - log.info("【根据sn号查询车辆实时信息】============logEntry转换后的对象: logEntry---【{}】" , JSON.toJSONString(logEntry)); - LogEntry.LocationValue value = logEntry.getValue(); - // 坐标转换 WGS84 转 GCJ02 - double[] doubles = CommonUtil.coordinateConvert(value.getLon(),value.getLat()); - BigDecimal lon = new BigDecimal(doubles[1]).setScale(8, RoundingMode.HALF_UP); - BigDecimal lat = new BigDecimal(doubles[0]).setScale(8, RoundingMode.HALF_UP); - rlDevice.setLongitude(lon.toString()); - rlDevice.setLatitude(lat.toString()); - } -// EModelVO rlModelVO = modelService.selectEModelByModelId(rlDevice.getModelId()); -// if(ObjectUtil.isNotNull(rlModelVO)){ -// if(StrUtil.isNotBlank(rlDevice.getVoltage())){ -// rlDevice.setRemainingMileage(CommonUtil.getRemainingMileage(rlDevice.getVoltage(),rlModelVO.getFullVoltage(),rlModelVO.getLowVoltage(),rlModelVO.getFullEndurance())); -// } -// rlDevice.setModel(rlModelVO.getModel()); -// List functionList = modelService.getFunctionListByModelId(rlDevice.getModelId()); -// List rlAccessoryVOS = accessoryService.selectRlAccessoryListByModelId(rlDevice.getModelId()); -// rlDevice.setFunctionList(functionList); -// rlDevice.setAccessorys(rlAccessoryVOS); -// } - return rlDevice; + return getLatestLocationBySn(rlDevice); } /** @@ -261,22 +237,18 @@ public class EDeviceServiceImpl extends ServiceImpl impl LogEntry.LocationValue value = logEntry.getValue(); // 坐标转换 WGS84 转 GCJ02 double[] doubles = CommonUtil.coordinateConvert(value.getLon(),value.getLat()); - BigDecimal lon = new BigDecimal(doubles[1]).setScale(8, RoundingMode.HALF_UP); - BigDecimal lat = new BigDecimal(doubles[0]).setScale(8, RoundingMode.HALF_UP); + BigDecimal lon = BigDecimal.valueOf(doubles[1]).setScale(8, RoundingMode.HALF_UP); + BigDecimal lat = BigDecimal.valueOf(doubles[0]).setScale(8, RoundingMode.HALF_UP); device.setLongitude(lon.toString()); device.setLatitude(lat.toString()); } -// EModelVO rlModelVO = modelService.selectEModelByModelId(device.getModelId()); -// if(ObjectUtil.isNotNull(rlModelVO)){ -// if(StrUtil.isNotBlank(device.getVoltage())){ -// device.setRemainingMileage(CommonUtil.getRemainingMileage(device.getVoltage(),rlModelVO.getFullVoltage(),rlModelVO.getLowVoltage(),rlModelVO.getFullEndurance())); -// } -// device.setModel(rlModelVO.getModel()); -// List functionList = modelService.getFunctionListByModelId(device.getModelId()); -// List rlAccessoryVOS = accessoryService.selectRlAccessoryListByModelId(device.getModelId()); -// device.setFunctionList(functionList); -// device.setAccessorys(rlAccessoryVOS); -// } + EModelVO rlModelVO = modelService.selectEModelByModelId(device.getModelId()); + if(ObjectUtil.isNotNull(rlModelVO)){ + if(StrUtil.isNotBlank(device.getVoltage())){ + device.setRemainingMileage(CommonUtil.getRemainingMileage(device.getVoltage(),rlModelVO.getFullVoltage(),rlModelVO.getLowVoltage(),rlModelVO.getFullEndurance())); + } + device.setModel(rlModelVO.getModel()); + } return device; } diff --git a/eride-system/src/main/java/com/ruoyi/system/service/impl/EModelServiceImpl.java b/eride-system/src/main/java/com/ruoyi/system/service/impl/EModelServiceImpl.java index c767ae2..583ecd6 100644 --- a/eride-system/src/main/java/com/ruoyi/system/service/impl/EModelServiceImpl.java +++ b/eride-system/src/main/java/com/ruoyi/system/service/impl/EModelServiceImpl.java @@ -176,9 +176,7 @@ public class EModelServiceImpl implements IEModelService etModel.setBrandName(brandService.selectEBrandByBrandId(etModel.getBrandId()).getName()); } int i = eModelRuleMapper.deleteEModelRuleByModelId(etModel.getModelId()); - if(i>0){ - saveModelRule(etModel); - } + saveModelRule(etModel); return eModelMapper.updateEModel(etModel); } diff --git a/eride-system/src/main/java/com/ruoyi/system/service/impl/EUserServiceImpl.java b/eride-system/src/main/java/com/ruoyi/system/service/impl/EUserServiceImpl.java index 3ee6bc9..2793818 100644 --- a/eride-system/src/main/java/com/ruoyi/system/service/impl/EUserServiceImpl.java +++ b/eride-system/src/main/java/com/ruoyi/system/service/impl/EUserServiceImpl.java @@ -202,9 +202,9 @@ public class EUserServiceImpl implements IEUserService{ public EUserVO selectUserById(Long userId) { EUserVO users = userMapper.selectUserById(userId); - if(ObjectUtil.isNull(users)){ - throw new ServiceException("没有该用户:"+userId); - } +// if(ObjectUtil.isNull(users)){ +// throw new ServiceException("没有该用户:"+userId); +// } return users; } diff --git a/eride-system/src/main/java/com/ruoyi/system/service/impl/WxPayService.java b/eride-system/src/main/java/com/ruoyi/system/service/impl/WxPayService.java index 9642f04..b72083e 100644 --- a/eride-system/src/main/java/com/ruoyi/system/service/impl/WxPayService.java +++ b/eride-system/src/main/java/com/ruoyi/system/service/impl/WxPayService.java @@ -1,5 +1,6 @@ package com.ruoyi.system.service.impl; +import cn.binarywang.wx.miniapp.bean.product.WxMiniAfterSaleOrder; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson2.JSON; @@ -11,6 +12,12 @@ import com.ruoyi.common.core.domain.entity.EUserVO; import com.ruoyi.common.core.redis.RedisLock; import com.ruoyi.common.enums.PayChannel; import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.pay.tm.TmPayService; +import com.ruoyi.common.pay.tm.enums.RefundStatus; +import com.ruoyi.common.pay.tm.vo.RefundInfo; +import com.ruoyi.common.pay.wx.Payable; +import com.ruoyi.common.pay.wx.RefundAble; +import com.ruoyi.common.utils.ServiceUtil; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.http.HttpUtils; import com.ruoyi.common.utils.uuid.IdUtils; @@ -38,6 +45,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; /** * 微信支付服务 @@ -66,6 +74,9 @@ public class WxPayService implements IWxPayService { @Resource private IERefundService etRefundService; + @Autowired + private TmPayService tmPayService; + private static final String CNY = "CNY"; private static final String PREPAY_LOCK = "prepay:"; @@ -84,7 +95,7 @@ public class WxPayService implements IWxPayService { String outTradeNo = null; if(PayChannel.CT_WX.equalsCode(channelVO.getCode())){ outTradeNo = IdUtils.getOrderNo("wx"); - }else if(PayChannel.TL_WX.equalsCode(channelVO.getCode())){ + }else if(PayChannel.TM_WX.equalsCode(channelVO.getCode())){ outTradeNo = IdUtils.getOrderNo("tlwx"); } String description = "租赁订单-"+billNo; @@ -95,30 +106,14 @@ public class WxPayService implements IWxPayService { order1.setPayChannel(payChannel); order1.setChannelName(channelVO.getName()); int updateEtOrder = orderService.updateRlOrder(order1); - if(updateEtOrder == 0){ - throw new ServiceException("更新订单outTradeNo失败"); - } + ServiceUtil.assertion(updateEtOrder == 0, "更新订单outTradeNo失败"); if(PayChannel.CT_WX.equalsCode(channelVO.getCode())){ - log.info("----------{}-------------","微信官方支付"); + log.info("【微信官方支付】-----------------------"); return getPrepayWithRequestPaymentResponse(order, user, channelVO, outTradeNo, description); - }else if(PayChannel.TL_WX.equalsCode(channelVO.getCode())){ -// todo 待接新的支付通道 -// log.info("----------{}-------------","通联微信支付"); -// if(StrUtil.isNotBlank(order.getOutTradeNo())){ -// // 关闭订单 -// sybPayService.closeOrderWx(order.getOutTradeNo()); -// } -// Payable payable = new Payable(); -// payable.setAmount(order.getPayFee().multiply(new BigDecimal(100)).longValue()); -// payable.setOutTradeNo(outTradeNo); -// payable.setAttach(JSON.toJSONString(new AttachVo(payType,user.getUserId(), ""))); -// payable.setDescription(description); -// payable.setOpenid(user.getWxopenid()); -// payable.setAppid(channelVO.getAppid()); -// PrepayWithRequestPaymentResponse res = sybPayService.prepayWxApp(payable); - PrepayWithRequestPaymentResponse res = null; - return res; + }else if(PayChannel.TM_WX.equalsCode(channelVO.getCode())){ + log.info("【太米微信支付】-----------------------"); + return getTMPaymentResponse(order, channelVO, outTradeNo, description, user); }else{ throw new ServiceException("支付渠道【"+channelVO.getCode()+"】暂不支持"); } @@ -127,6 +122,20 @@ public class WxPayService implements IWxPayService { } } + private static PrepayWithRequestPaymentResponse getTMPaymentResponse(EOrder order, ChannelVO channelVO, String outTradeNo, String description, EUserVO user) { + if(StrUtil.isNotBlank(order.getOutTradeNo())){ + // 关闭订单 + TmPayService.closeOrder(channelVO, order.getOutTradeNo()); + } + Payable payable = new Payable(); + payable.setAmount(order.getPayFee().multiply(new BigDecimal(100)).longValue()); + payable.setOutTradeNo(outTradeNo); + payable.setDescription(description); + payable.setOpenid(user.getWxopenid()); + payable.setAppid(channelVO.getAppid()); + return TmPayService.pay(channelVO, payable); + } + private String getOpenId(String jsCode,String appId,String secret) { //根据jsCode换取openid String url = StrUtil.format("https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code", appId, secret, jsCode); @@ -147,7 +156,7 @@ public class WxPayService implements IWxPayService { request.setAppid(channelVO.getAppid()); request.setMchid(channelVO.getMerchantId()); request.setDescription(description); - log.info("支付渠道------"+JSON.toJSON(channelVO)); + log.info("支付渠道------{}", JSON.toJSON(channelVO)); request.setNotifyUrl(channelVO.getNotifyUrl()); request.setPayer(getPayer(user.getWxopenid())); JsapiServiceExtension jsapiServiceExtension = getJsapiServiceExtension(channelVO); @@ -329,12 +338,11 @@ public class WxPayService implements IWxPayService { public void refund(EOrder etOrder, String reason, BigDecimal amount, String outRefundNo) { if(!etOrder.getPaid().equals(ServiceConstants.ORDER_PAY_STATUS_PAID)) throw new ServiceException("订单状态异常"); ChannelVO channelVO = etChannelService.selectSmChannelByChannelId(etOrder.getPayChannel()); - if (channelVO == null) { - throw new ServiceException("支付渠道不存在: " + etOrder.getPayChannel()); - } + + ServiceUtil.assertion(ObjectUtil.isNull(channelVO), "支付渠道不存在: " + etOrder.getPayChannel()); if(PayChannel.CT_WX.equalsCode(channelVO.getCode())){ - log.info("----------{}-------------","微信官方退款"); + log.info("【微信官方退款】-----------------------"); CreateRequest request = new CreateRequest(); request.setOutTradeNo(etOrder.getOutTradeNo()); request.setOutRefundNo(outRefundNo); @@ -345,24 +353,19 @@ public class WxPayService implements IWxPayService { RefundService refundService = getRefundService(channelVO); Refund refund = refundService.create(request); log.info("【退款】微信返回结果:【{}】",JSON.toJSONString(refund)); - }else if(PayChannel.TL_WX.equalsCode(channelVO.getCode())){ - throw new ServiceException("支付渠道【"+channelVO.getCode()+"】暂不支持"); -// log.info("----------{}-------------","通联微信退款"); -// RefundAble refundAble = new RefundAble(); -// refundAble.setOutTradeNo(etOrder.getOutTradeNo()); -// refundAble.setOutRefundNo(outRefundNo); -// refundAble.setReason(reason); -// refundAble.setAmount(amount.multiply(new BigDecimal(100)).longValue()); -// Map refundResult = sybPayService.refundWx(refundAble); -// String trxStatus = refundResult.get("trxstatus"); -// // 当状态不为空,则判断是否处理退款成功 -// if (trxStatus != null) { -// ServiceUtil.assertion(!SybTrxStatus.isSuccess(trxStatus), "发起退款失败:" + refundResult.get("errmsg")); -// // 通联退款是同步通知,直接处理退款成功 -// scheduledExecutorService.schedule(() -> { -// handleRefundSuccess(outRefundNo); -// }, 0, TimeUnit.SECONDS); -// } + }else if(PayChannel.TM_WX.equalsCode(channelVO.getCode())){ + log.info("【太米微信退款】-----------------------"); + RefundAble refundAble = new RefundAble(); + refundAble.setOutTradeNo(etOrder.getOutTradeNo()); + refundAble.setOutRefundNo(outRefundNo); + refundAble.setReason(reason); + refundAble.setAmount(amount.multiply(new BigDecimal(100)).longValue()); + log.info("【退款】请求太米参数:【{}】",JSON.toJSONString(refundAble)); + RefundInfo refund = TmPayService.refund(channelVO, refundAble); + ServiceUtil.assertion(!RefundStatus.isSuccess(refund.getRefundStatus().getCode()), "发起退款失败:" + refund.getRefundMessage()); + scheduledExecutorService.schedule(() -> { + handleRefundSuccess(outRefundNo); + }, 0, TimeUnit.SECONDS); }else{ throw new ServiceException("支付渠道【"+channelVO.getCode()+"】暂不支持"); } diff --git a/eride-system/src/main/resources/mapper/system/EOrderMapper.xml b/eride-system/src/main/resources/mapper/system/EOrderMapper.xml index 33e12d9..1683326 100644 --- a/eride-system/src/main/resources/mapper/system/EOrderMapper.xml +++ b/eride-system/src/main/resources/mapper/system/EOrderMapper.xml @@ -7,11 +7,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select order_id, order_no, out_trade_no, user_id, user_name, real_name, phone, rule_id, device_mac, sn, pay_time, pay_type, paid, type, total_fee, pay_fee, deposit, overdue_fee, dispatch_fee,delivery_fee, - lease_fee, mark, duration, status, create_time, return_time, deposit_deduction, deposit_order_no, deduction_amount, used_sn, change_reason, - auto_refund_deposit, rental_unit, handling_charge, platform_service_fee, operator_dividend, pay_channel, channel_name, delivery_method, pickup_time, + select order_id, order_no, out_trade_no, user_id, user_name, real_name, phone, rule_id, device_mac, sn, pay_time, pay_type, paid, type, total_fee, pay_fee, deposit, overdue_fee, dispatch_fee, + lease_fee, mark, duration, status, create_time, return_time, deduction_amount,rental_unit, handling_charge, platform_service_fee, operator_dividend, pay_channel, channel_name, pickup_time, , store_name, merchant_id, pickup_city, pickup_loc, pickup_lon, pickup_lat, model_id, model, expiry_time, original_order_no, num, price, `explain`, - instructions, out_unit, out_price,return_type,return_method,return_address,auto_cancel_time,cost, is_overdue,is_send_msg from e_order + instructions, out_unit, out_price,return_type,return_address,auto_cancel_time,cost, is_overdue,is_send_msg from e_order @@ -35,7 +34,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" o.deposit, o.overdue_fee, o.dispatch_fee, - o.delivery_fee, o.lease_fee, o.model_id, o.model, @@ -44,19 +42,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" o.status, o.create_time, o.return_time, - o.deposit_deduction, - o.deposit_order_no, o.deduction_amount, - o.used_sn, - o.change_reason, - o.auto_refund_deposit, o.rental_unit, o.handling_charge, o.platform_service_fee, o.operator_dividend, o.pay_channel, o.channel_name, - o.delivery_method, o.pickup_time, o.store_id, o.store_name, @@ -76,7 +68,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" mo.model, r.rental_unit as rentalUnit, o.return_type, - o.return_method, o.return_address, o.auto_cancel_time, o.merchant_id, @@ -132,21 +123,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and o.pay_fee = #{payFee} and o.deposit = #{deposit} and o.dispatch_fee = #{dispatchFee} - and o.delivery_fee = #{deliveryFee} and o.lease_fee = #{leaseFee} and o.mark = #{mark} and o.duration = #{duration} and o.status = #{status} and o.return_time = #{returnTime} - and o.deposit_deduction = #{depositDeduction} and o.deduction_amount = #{deductionAmount} - and o.auto_refund_deposit = #{autoRefundDeposit} and o.rental_unit = #{rentalUnit} and o.handling_charge = #{handlingCharge} and o.platform_service_fee = #{platformServiceFee} and o.operator_dividend = #{operatorDividend} and o.pay_channel = #{payChannel} - and o.delivery_method = #{deliveryMethod} and o.pickup_time = #{pickupTime} and o.store_id = #{storeId} and o.store_name = #{storeName} @@ -260,7 +247,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" deposit, overdue_fee, dispatch_fee, - delivery_fee, lease_fee, model_id, model, @@ -269,18 +255,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" status, create_time, return_time, - deposit_deduction, - deposit_order_no, deduction_amount, - used_sn, - change_reason, - auto_refund_deposit, rental_unit, handling_charge, platform_service_fee, operator_dividend, pay_channel, - delivery_method, pickup_time, store_id, store_name, @@ -298,7 +278,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" out_unit, out_price, return_type, - return_method, return_address, return_lon, return_lat, @@ -325,7 +304,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{deposit}, #{overdueFee}, #{dispatchFee}, - #{deliveryFee}, #{leaseFee}, #{modelId}, #{model}, @@ -334,18 +312,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{status}, #{createTime}, #{returnTime}, - #{depositDeduction}, - #{depositOrderNo}, #{deductionAmount}, - #{usedSn}, - #{changeReason}, - #{autoRefundDeposit}, #{rentalUnit}, #{handlingCharge}, #{platformServiceFee}, #{operatorDividend}, #{payChannel}, - #{deliveryMethod}, #{pickupTime}, #{storeId}, #{storeName}, @@ -363,7 +335,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{outUnit}, #{outPrice}, #{returnType}, - #{returnMethod}, #{returnAddress}, #{returnLon}, #{returnLat}, @@ -394,7 +365,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" deposit = #{deposit}, overdue_fee = #{overdueFee}, dispatch_fee = #{dispatchFee}, - delivery_fee = #{deliveryFee}, lease_fee = #{leaseFee}, model_id = #{modelId}, model = #{model}, @@ -403,19 +373,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" status = #{status}, create_time = #{createTime}, return_time = #{returnTime}, - deposit_deduction = #{depositDeduction}, - deposit_order_no = #{depositOrderNo}, deduction_amount = #{deductionAmount}, - used_sn = #{usedSn}, - change_reason = #{changeReason}, - auto_refund_deposit = #{autoRefundDeposit}, rental_unit = #{rentalUnit}, handling_charge = #{handlingCharge}, platform_service_fee = #{platformServiceFee}, operator_dividend = #{operatorDividend}, pay_channel = #{payChannel}, channel_name = #{channelName}, - delivery_method = #{deliveryMethod}, pickup_time = #{pickupTime}, store_id = #{storeId}, store_name = #{storeName}, @@ -433,7 +397,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" out_unit = #{outUnit}, out_price = #{outPrice}, return_type = #{returnType}, - return_method = #{returnMethod}, return_address = #{returnAddress}, return_lon = #{returnLon}, return_lat = #{returnLat}, @@ -466,7 +429,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" deposit = #{deposit}, overdue_fee = #{overdueFee}, dispatch_fee = #{dispatchFee}, - delivery_fee = #{deliveryFee}, lease_fee = #{leaseFee}, model_id = #{modelId}, model, @@ -475,19 +437,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" status = #{status}, create_time = #{createTime}, return_time = #{returnTime}, - deposit_deduction = #{depositDeduction}, - deposit_order_no = #{depositOrderNo}, deduction_amount = #{deductionAmount}, - used_sn = #{usedSn}, - change_reason = #{changeReason}, - auto_refund_deposit = #{autoRefundDeposit}, rental_unit = #{rentalUnit}, handling_charge = #{handlingCharge}, platform_service_fee = #{platformServiceFee}, operator_dividend = #{operatorDividend}, pay_channel = #{payChannel}, channel_name = #{channelName}, - delivery_method = #{deliveryMethod}, pickup_time = #{pickupTime}, store_id = #{storeId}, store_name = #{storeName}, @@ -505,7 +461,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" out_unit = #{outUnit}, out_price = #{outPrice}, return_type = #{returnType}, - return_method = #{returnMethod}, return_address = #{returnAddress}, return_lon = #{returnLon}, return_lat = #{returnLat}, diff --git a/eride-system/src/main/resources/mapper/system/ERefundMapper.xml b/eride-system/src/main/resources/mapper/system/ERefundMapper.xml index 8b90361..41150b2 100644 --- a/eride-system/src/main/resources/mapper/system/ERefundMapper.xml +++ b/eride-system/src/main/resources/mapper/system/ERefundMapper.xml @@ -7,11 +7,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select id, refund_no, order_no, user_id, amount, dispatch_fee, delivery_fee, lease_fee, deposit, type, reason, create_time, item_desc,refund_result, merchant_id from e_refund + select id, refund_no, order_no, user_id, amount, dispatch_fee, lease_fee, deposit, type, reason, create_time, item_desc,refund_result, merchant_id from e_refund