渠道、退款、支付

This commit is contained in:
邱贞招 2024-12-16 09:13:24 +08:00
parent da05a550ef
commit c3ce7302a7
31 changed files with 1044 additions and 356 deletions

View File

@ -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<EDeviceVO> asDevices = new ArrayList<>();

View File

@ -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));
}
}

View File

@ -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<String, Object> 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<String, Object> 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) {

View File

@ -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<EOrderVO> list = rlOrderService.selectRlOrderList(rlOrder);
List<EOrderVO> 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<EOrderVO> list = rlOrderService.selectRlOrderList(rlOrder);
List<EOrderVO> list = orderService.selectRlOrderList(rlOrder);
ExcelUtil<EOrderVO> util = new ExcelUtil<EOrderVO>(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));
}
}

View File

@ -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----------------------------*/
}

View File

@ -13,7 +13,7 @@ import lombok.Getter;
@AllArgsConstructor
public enum PayChannel {
CT_WX("ctwx", "创特微信支付"),
TL_WX("tlwx", "通联微信支付");
TM_WX("tmwx", "太米微信支付");
private final String code;

View File

@ -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<String, Object> 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<String,Object> 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<String, String> body = new HashMap<String, String>();
// 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<String, Object> 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<String, Object> 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<String, String> headerData = new HashMap<String, String>();
headerData.put("Content-Type", "application/json");
String response = HttpUtils.sendPostWithHeaders(HTTP + url, headerData,JSON.toJSONString(body));
System.out.println("API Response: " + response);
}
}

View File

@ -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();
}

View File

@ -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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, String> 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<String, Object> 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);
}
}

View File

@ -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-Za-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<String, Object> map) {
List<Entry<String, Object>> infoIds = new ArrayList<>(map.entrySet());
// 对所有传入参数按照字段名的 ASCII 码从小到大排序字典序
Collections.sort(infoIds, new Comparator<Entry<String, Object>>() {
public int compare(Entry<String, Object> o1, Entry<String, Object> o2) {
return o1.getKey().compareToIgnoreCase(o2.getKey());
}
});
// 构造签名键值对的格式
StringBuilder sb = new StringBuilder();
for (Entry<String, Object> 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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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; // 创建时间
}

View File

@ -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支付宝收款码
* webWeb页面mini小程序posPOS机
* pcPCdesktop台式消费机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;
}

View File

@ -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<String, String> 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<String, String> 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方法的请求
*

View File

@ -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()));
}
}

View File

@ -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;
/**
* 还车地址
*/

View File

@ -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);

View File

@ -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()+"】的支付渠道未配置");

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 {
}

View File

@ -51,8 +51,8 @@ public class ERefund extends BaseEntity
/** 调度费 */
private BigDecimal dispatchFee;
/** 配送费 */
private BigDecimal deliveryFee;
// /** 配送费 */
// private BigDecimal deliveryFee;
/** 租赁费 */
private BigDecimal leaseFee;

View File

@ -43,7 +43,7 @@ public interface IEDeviceService extends IService<EDevice>
* @param sn 设备主键
* @return 设备
*/
public EDevice selectEDeviceBySn(String sn);
public EDeviceVO selectEDeviceBySn(String sn);
/**
* 查询设备列表

View File

@ -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<TransferDetailInput> transferDetailInputs);
/**
* 根据退款单号查询退款信息

View File

@ -190,8 +190,8 @@ public class EDeviceServiceImpl extends ServiceImpl<EDeviceMapper, EDevice> 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<EDeviceMapper, EDevice> 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<EFunction> functionList = modelService.getFunctionListByModelId(rlDevice.getModelId());
// List<EAccessoryVO> 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<EDeviceMapper, EDevice> 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<EFunction> functionList = modelService.getFunctionListByModelId(device.getModelId());
// List<EAccessoryVO> 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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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<String, String> 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()+"】暂不支持");
}

View File

@ -7,11 +7,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<resultMap type="EOrderVO" id="RlOrderResult" autoMapping="true"/>
<sql id="selectRlOrderVo">
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
</sql>
<sql id="selectRlOrderDetail">
@ -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"
<if test="payFee != null"> and o.pay_fee = #{payFee}</if>
<if test="deposit != null"> and o.deposit = #{deposit}</if>
<if test="dispatchFee != null"> and o.dispatch_fee = #{dispatchFee}</if>
<if test="deliveryFee != null"> and o.delivery_fee = #{deliveryFee}</if>
<if test="leaseFee != null"> and o.lease_fee = #{leaseFee}</if>
<if test="mark != null and mark != ''"> and o.mark = #{mark}</if>
<if test="duration != null"> and o.duration = #{duration}</if>
<if test="status != null and status != ''"> and o.status = #{status}</if>
<if test="returnTime != null"> and o.return_time = #{returnTime}</if>
<if test="depositDeduction != null and depositDeduction != ''"> and o.deposit_deduction = #{depositDeduction}</if>
<if test="deductionAmount != null"> and o.deduction_amount = #{deductionAmount}</if>
<if test="autoRefundDeposit != null"> and o.auto_refund_deposit = #{autoRefundDeposit}</if>
<if test="rentalUnit != null and rentalUnit != ''"> and o.rental_unit = #{rentalUnit}</if>
<if test="handlingCharge != null"> and o.handling_charge = #{handlingCharge}</if>
<if test="platformServiceFee != null"> and o.platform_service_fee = #{platformServiceFee}</if>
<if test="operatorDividend != null"> and o.operator_dividend = #{operatorDividend}</if>
<if test="payChannel != null"> and o.pay_channel = #{payChannel}</if>
<if test="deliveryMethod != null"> and o.delivery_method = #{deliveryMethod}</if>
<if test="pickupTime != null"> and o.pickup_time = #{pickupTime}</if>
<if test="storeId != null"> and o.store_id = #{storeId}</if>
<if test="storeName != null and storeName != ''"> and o.store_name = #{storeName}</if>
@ -260,7 +247,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="deposit != null">deposit,</if>
<if test="overdueFee != null">overdue_fee,</if>
<if test="dispatchFee != null">dispatch_fee,</if>
<if test="deliveryFee != null">delivery_fee,</if>
<if test="leaseFee != null">lease_fee,</if>
<if test="modelId != null">model_id,</if>
<if test="model != null">model,</if>
@ -269,18 +255,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null">status,</if>
<if test="createTime != null">create_time,</if>
<if test="returnTime != null">return_time,</if>
<if test="depositDeduction != null">deposit_deduction,</if>
<if test="depositOrderNo != null">deposit_order_no,</if>
<if test="deductionAmount != null">deduction_amount,</if>
<if test="usedSn != null">used_sn,</if>
<if test="changeReason != null">change_reason,</if>
<if test="autoRefundDeposit != null">auto_refund_deposit,</if>
<if test="rentalUnit != null">rental_unit,</if>
<if test="handlingCharge != null">handling_charge,</if>
<if test="platformServiceFee != null">platform_service_fee,</if>
<if test="operatorDividend != null">operator_dividend,</if>
<if test="payChannel != null">pay_channel,</if>
<if test="deliveryMethod != null">delivery_method,</if>
<if test="pickupTime != null">pickup_time,</if>
<if test="storeId != null">store_id,</if>
<if test="storeName != null">store_name,</if>
@ -298,7 +278,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="outUnit != null">out_unit,</if>
<if test="outPrice != null">out_price,</if>
<if test="returnType != null">return_type,</if>
<if test="returnMethod != null">return_method,</if>
<if test="returnAddress != null">return_address,</if>
<if test="returnLon != null">return_lon,</if>
<if test="returnLat != null">return_lat,</if>
@ -325,7 +304,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="deposit != null">#{deposit},</if>
<if test="overdueFee != null">#{overdueFee},</if>
<if test="dispatchFee != null">#{dispatchFee},</if>
<if test="deliveryFee != null">#{deliveryFee},</if>
<if test="leaseFee != null">#{leaseFee},</if>
<if test="modelId != null">#{modelId},</if>
<if test="model != null">#{model},</if>
@ -334,18 +312,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null">#{status},</if>
<if test="createTime != null">#{createTime},</if>
<if test="returnTime != null">#{returnTime},</if>
<if test="depositDeduction != null">#{depositDeduction},</if>
<if test="depositOrderNo != null">#{depositOrderNo},</if>
<if test="deductionAmount != null">#{deductionAmount},</if>
<if test="usedSn != null">#{usedSn},</if>
<if test="changeReason != null">#{changeReason},</if>
<if test="autoRefundDeposit != null">#{autoRefundDeposit},</if>
<if test="rentalUnit != null">#{rentalUnit},</if>
<if test="handlingCharge != null">#{handlingCharge},</if>
<if test="platformServiceFee != null">#{platformServiceFee},</if>
<if test="operatorDividend != null">#{operatorDividend},</if>
<if test="payChannel != null">#{payChannel},</if>
<if test="deliveryMethod != null">#{deliveryMethod},</if>
<if test="pickupTime != null">#{pickupTime},</if>
<if test="storeId != null">#{storeId},</if>
<if test="storeName != null">#{storeName},</if>
@ -363,7 +335,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="outUnit != null">#{outUnit},</if>
<if test="outPrice != null">#{outPrice},</if>
<if test="returnType != null">#{returnType},</if>
<if test="returnMethod != null">#{returnMethod},</if>
<if test="returnAddress != null">#{returnAddress},</if>
<if test="returnLon != null">#{returnLon},</if>
<if test="returnLat != null">#{returnLat},</if>
@ -394,7 +365,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="deposit != null">deposit = #{deposit},</if>
<if test="overdueFee != null">overdue_fee = #{overdueFee},</if>
<if test="dispatchFee != null">dispatch_fee = #{dispatchFee},</if>
<if test="deliveryFee != null">delivery_fee = #{deliveryFee},</if>
<if test="leaseFee != null">lease_fee = #{leaseFee},</if>
<if test="modelId != null">model_id = #{modelId},</if>
<if test="model != null">model = #{model},</if>
@ -403,19 +373,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null">status = #{status},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="returnTime != null">return_time = #{returnTime},</if>
<if test="depositDeduction != null">deposit_deduction = #{depositDeduction},</if>
<if test="depositOrderNo != null">deposit_order_no = #{depositOrderNo},</if>
<if test="deductionAmount != null">deduction_amount = #{deductionAmount},</if>
<if test="usedSn != null">used_sn = #{usedSn},</if>
<if test="changeReason != null">change_reason = #{changeReason},</if>
<if test="autoRefundDeposit != null">auto_refund_deposit = #{autoRefundDeposit},</if>
<if test="rentalUnit != null">rental_unit = #{rentalUnit},</if>
<if test="handlingCharge != null">handling_charge = #{handlingCharge},</if>
<if test="platformServiceFee != null">platform_service_fee = #{platformServiceFee},</if>
<if test="operatorDividend != null">operator_dividend = #{operatorDividend},</if>
<if test="payChannel != null">pay_channel = #{payChannel},</if>
<if test="channelName != null">channel_name = #{channelName},</if>
<if test="deliveryMethod != null">delivery_method = #{deliveryMethod},</if>
<if test="pickupTime != null">pickup_time = #{pickupTime},</if>
<if test="storeId != null">store_id = #{storeId},</if>
<if test="storeName != null">store_name = #{storeName},</if>
@ -433,7 +397,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="outUnit != null">out_unit = #{outUnit},</if>
<if test="outPrice != null">out_price = #{outPrice},</if>
<if test="returnType != null">return_type = #{returnType},</if>
<if test="returnMethod != null">return_method = #{returnMethod},</if>
<if test="returnAddress != null">return_address = #{returnAddress},</if>
<if test="returnLon != null">return_lon = #{returnLon},</if>
<if test="returnLat != null">return_lat = #{returnLat},</if>
@ -466,7 +429,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="deposit != null">deposit = #{deposit},</if>
<if test="overdueFee != null">overdue_fee = #{overdueFee},</if>
<if test="dispatchFee != null">dispatch_fee = #{dispatchFee},</if>
<if test="deliveryFee != null">delivery_fee = #{deliveryFee},</if>
<if test="leaseFee != null">lease_fee = #{leaseFee},</if>
<if test="modelId != null">model_id = #{modelId},</if>
<if test="model != null">model,</if>
@ -475,19 +437,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null">status = #{status},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="returnTime != null">return_time = #{returnTime},</if>
<if test="depositDeduction != null">deposit_deduction = #{depositDeduction},</if>
<if test="depositOrderNo != null">deposit_order_no = #{depositOrderNo},</if>
<if test="deductionAmount != null">deduction_amount = #{deductionAmount},</if>
<if test="usedSn != null">used_sn = #{usedSn},</if>
<if test="changeReason != null">change_reason = #{changeReason},</if>
<if test="autoRefundDeposit != null">auto_refund_deposit = #{autoRefundDeposit},</if>
<if test="rentalUnit != null">rental_unit = #{rentalUnit},</if>
<if test="handlingCharge != null">handling_charge = #{handlingCharge},</if>
<if test="platformServiceFee != null">platform_service_fee = #{platformServiceFee},</if>
<if test="operatorDividend != null">operator_dividend = #{operatorDividend},</if>
<if test="payChannel != null">pay_channel = #{payChannel},</if>
<if test="channelName != null">channel_name = #{channelName},</if>
<if test="deliveryMethod != null">delivery_method = #{deliveryMethod},</if>
<if test="pickupTime != null">pickup_time = #{pickupTime},</if>
<if test="storeId != null">store_id = #{storeId},</if>
<if test="storeName != null">store_name = #{storeName},</if>
@ -505,7 +461,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="outUnit != null">out_unit = #{outUnit},</if>
<if test="outPrice != null">out_price = #{outPrice},</if>
<if test="returnType != null">return_type = #{returnType},</if>
<if test="returnMethod != null">return_method = #{returnMethod},</if>
<if test="returnAddress != null">return_address = #{returnAddress},</if>
<if test="returnLon != null">return_lon = #{returnLon},</if>
<if test="returnLat != null">return_lat = #{returnLat},</if>

View File

@ -7,11 +7,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<resultMap type="ERefundVO" id="EtRefundResult" autoMapping="true" />
<sql id="selectEtRefundVo">
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
</sql>
<select id="selectEtRefundList" parameterType="ERefund" resultMap="EtRefundResult">
select r.id, r.refund_no, r.order_no, r.user_id, u.user_name userName, r.amount, r.dispatch_fee, r.delivery_fee,
select r.id, r.refund_no, r.order_no, r.user_id, u.user_name userName, r.amount, r.dispatch_fee,
r.lease_fee, r.deposit, r.type, r.reason, r.create_time, r.item_desc,r.refund_result,r.merchant_id from e_refund r
INNER JOIN e_order o on o.order_no = r.order_no
left join e_user u on u.user_id = r.user_id
@ -55,7 +55,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null">user_id,</if>
<if test="amount != null">amount,</if>
<if test="dispatchFee != null">dispatch_fee,</if>
<if test="deliveryFee != null">delivery_fee,</if>
<if test="leaseFee != null">lease_fee,</if>
<if test="type != null">type,</if>
<if test="reason != null">reason,</if>
@ -72,7 +71,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null">#{userId},</if>
<if test="amount != null">#{amount},</if>
<if test="dispatchFee != null">#{dispatchFee},</if>
<if test="deliveryFee != null">#{deliveryFee},</if>
<if test="leaseFee != null">#{leaseFee},</if>
<if test="type != null">#{type},</if>
<if test="reason != null">#{reason},</if>
@ -92,7 +90,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null">user_id = #{userId},</if>
<if test="amount != null">amount = #{amount},</if>
<if test="dispatchFee != null">dispatch_fee = #{dispatchFee},</if>
<if test="deliveryFee != null">delivery_fee = #{deliveryFee},</if>
<if test="leaseFee != null">lease_fee = #{leaseFee},</if>
<if test="deposit != null">deposit = #{deposit},</if>
<if test="type != null">type = #{type},</if>
@ -110,7 +107,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null">user_id = #{userId},</if>
<if test="amount != null">amount = #{amount},</if>
<if test="dispatchFee != null">dispatch_fee = #{dispatchFee},</if>
<if test="deliveryFee != null">delivery_fee = #{deliveryFee},</if>
<if test="leaseFee != null">lease_fee = #{leaseFee},</if>
<if test="deposit != null">deposit = #{deposit},</if>
<if test="type != null">type = #{type},</if>
@ -155,7 +151,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
SELECT
COALESCE(SUM(amount), 0) AS total_refund_amount,
COALESCE(SUM(dispatch_fee), 0) AS total_dispatch_fee,
COALESCE(SUM(delivery_fee), 0) AS total_delivery_fee,
COALESCE(SUM(lease_fee), 0) AS total_lease_fee,
COALESCE(SUM(deposit), 0) AS total_deposit
FROM