1. 联调

This commit is contained in:
邱贞招 2024-06-07 21:31:39 +08:00
parent 7129d0aa5d
commit 3aa7145e58
30 changed files with 927 additions and 436 deletions

View File

@ -300,10 +300,10 @@ public class AppController extends BaseController
* 查询退款是否成功
*/
@GetMapping("/queryByOutRefundNo")
public AjaxResult queryByOutRefundNo(String outRefundNo)
public AjaxResult queryByOutRefundNo(Long areaId,String outRefundNo)
{
logger.info("查询退款是否成功【outRefundNo="+outRefundNo+"");
Refund refund = wxPayService.queryByOutRefundNo(outRefundNo);
Refund refund = wxPayService.queryByOutRefundNo(areaId,outRefundNo);
return AjaxResult.success(refund);
}

View File

@ -147,6 +147,13 @@ public class AppVerifyController extends BaseController
if(order.getRuleId()==null){
return error("=============================================ruleId未传=============================================");
}
// 判断该订单是否已结束
EtOrder etOrder = etOrderService.selectEtOrderByOrderNo(order.getOrderNo());
if(ObjectUtil.isNotNull(etOrder)){
if(ServiceConstants.ORDER_STATUS_ORDER_END.equals(etOrder.getStatus())){
return error("订单已结束,请重新扫码");
}
}
AsDevice asDevice = asDeviceService.selectAsDeviceBySn(order.getSn());
EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(asDevice.getAreaId());
//实名判断

View File

@ -167,8 +167,9 @@ public class ReceiveController {
/** 3.超出运营区外断电*/
boolean isAreaZone = asDeviceService.isAreaZone(device.getSn(), area);
if(!isAreaZone){
String isAdminUnlocking = device.getIsAdminUnlocking();// 是否管理员开锁
String areaOutOutage = area.getAreaOutOutage();
if (areaOutOutage.equals("1") && value.getStatus() != 3) { // 超出营运区断电
if (areaOutOutage.equals("1") && value.getStatus() != 3 && !isAdminUnlocking.equals("1")) { // 超出营运区断电
log.info("超出营运区断电命令--SN" + device.getSn());
asDeviceService.sendCommand(device.getMac(), Token.getToken(), IotConstants.COMMAND_QLOSE, "超出营运区断电");
}

View File

@ -190,7 +190,7 @@ wx:
# 通知回调地址
# notifyUrl: https://dianche.chuantewulian.cn/prod-api/payment/callback/wechat/
notifyUrl: http://124.221.246.124:2289/payment/callback/wechat/
# 密钥所在位置
# 密钥所在位置 \usr\local\electripper\wxpay\ysd\apiclient_key.pem
privateKeyPath: D:/wxpay/apiclient_key.pem
# 证书序列号 7DDDDEED9A8DF3DD8363E49D636D3F551FFC8A19
merchantSerialNumber: 66910F800A60768020F07D39A56AE701574A16AE
@ -233,4 +233,3 @@ et:
appcode: 32b6c6445b1a42ed862dd4202392c47d
repairAdmin: wx
operateAdmin: root
profitSharing: true

View File

@ -1,141 +1,142 @@
package com.ruoyi.common.config;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.service.brandprofitsharing.BrandProfitSharingService;
import com.wechat.pay.java.service.payments.app.AppService;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.profitsharing.ProfitsharingService;
import com.wechat.pay.java.service.refund.RefundService;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 微信支付配置
* @author
* 2024/3/11
*/
@Configuration
@Getter
public class WxPayConfig {
// 小程序id
@Value("${wx.pay.appId}")
private String appId;
// 商户id
@Value("${wx.pay.merchantId}")
private String merchantId;
// apiV3私钥
@Value("${wx.pay.apiV3Key}")
private String apiV3Key;
// 通知回调地址
@Value("${wx.pay.notifyUrl}")
private String notifyUrl;
// 退款通知回调地址
@Value("${wx.refund.notifyUrl}")
private String refundNotifyUrl;
// 私钥证书路径
@Value("${wx.pay.privateKeyPath}")
private String privateKeyPath;
// 证书序列号
@Value("${wx.pay.merchantSerialNumber}")
private String merchantSerialNumber;
@Bean
public AppService appService () {
// 初始化商户配置
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
// 初始化服务
return new AppService.Builder().config(config).build();
}
@Bean
public JsapiService jsapiService() {
// 初始化商户配置
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
// 初始化服务
return new JsapiService.Builder().config(config).build();
}
@Bean
public JsapiServiceExtension jsapiServiceExtension() {
// 初始化商户配置
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
// 初始化服务
return new JsapiServiceExtension
.Builder()
.config(config)
.signType("RSA") // 不填默认为RSA
.build();
}
// 微信通知解析器
@Bean
public NotificationParser notificationParser() {
NotificationConfig config = new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
return new NotificationParser(config);
}
@Bean
public RefundService refundService() {
// 初始化商户配置
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
// 初始化服务
return new RefundService.Builder().config(config).build();
}
// 分账服务
@Bean
public ProfitsharingService brandProfitSharingService() {
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
// 使用 com.wechat.pay.java.core.util中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
// 初始化服务
return new ProfitsharingService.Builder().config(config).build();
}
}
//package com.ruoyi.common.config;
//
//import com.wechat.pay.java.core.Config;
//import com.wechat.pay.java.core.RSAAutoCertificateConfig;
//import com.wechat.pay.java.core.notification.NotificationConfig;
//import com.wechat.pay.java.core.notification.NotificationParser;
//import com.wechat.pay.java.service.brandprofitsharing.BrandProfitSharingService;
//import com.wechat.pay.java.service.payments.app.AppService;
//import com.wechat.pay.java.service.payments.jsapi.JsapiService;
//import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
//import com.wechat.pay.java.service.profitsharing.ProfitsharingService;
//import com.wechat.pay.java.service.refund.RefundService;
//import lombok.Getter;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.stereotype.Service;
//
///**
// * 微信支付配置
// * @author
// * 2024/3/11
// */
//@Configuration
//@Getter
//public class WxPayConfig {
//
//// // 小程序id
//// @Value("${wx.pay.appId}")
//// private String appId;
////
//// // 商户id
//// @Value("${wx.pay.merchantId}")
//// private String merchantId;
////
//// // apiV3私钥
//// @Value("${wx.pay.apiV3Key}")
//// private String apiV3Key;
////
//// // 通知回调地址
//// @Value("${wx.pay.notifyUrl}")
//// private String notifyUrl;
////
//// // 退款通知回调地址
//// @Value("${wx.refund.notifyUrl}")
//// private String refundNotifyUrl;
////
//// // 私钥证书路径
//// @Value("${wx.pay.privateKeyPath}")
//// private String privateKeyPath;
////
//// // 证书序列号
//// @Value("${wx.pay.merchantSerialNumber}")
//// private String merchantSerialNumber;
////
//// @Bean
//// public AppService appService () {
//// // 初始化商户配置
//// Config config = new RSAAutoCertificateConfig.Builder()
//// .merchantId(merchantId)
//// // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
//// .privateKeyFromPath(privateKeyPath)
//// .merchantSerialNumber(merchantSerialNumber)
//// .apiV3Key(apiV3Key)
//// .build();
//// // 初始化服务
//// return new AppService.Builder().config(config).build();
//// }
////
// @Bean
// public JsapiService jsapiService() {
// // 初始化商户配置
// Config config = new RSAAutoCertificateConfig.Builder()
// .merchantId(merchantId)
// // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
// .privateKeyFromPath(privateKeyPath)
// .merchantSerialNumber(merchantSerialNumber)
// .apiV3Key(apiV3Key)
// .build();
// // 初始化服务
// return new JsapiService.Builder().config(config).build();
// }
//
// @Bean
// public JsapiServiceExtension jsapiServiceExtension() {
// // 初始化商户配置
// Config config = new RSAAutoCertificateConfig.Builder()
// .merchantId(merchantId)
// // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
// .privateKeyFromPath(privateKeyPath)
// .merchantSerialNumber(merchantSerialNumber)
// .apiV3Key(apiV3Key)
// .build();
// // 初始化服务
// return new JsapiServiceExtension
// .Builder()
// .config(config)
// .signType("RSA") // 不填默认为RSA
// .build();
// }
//
// // 微信通知解析器
// @Bean
// public NotificationParser notificationParser() {
// NotificationConfig config = new RSAAutoCertificateConfig.Builder()
// .merchantId(merchantId)
// .privateKeyFromPath(privateKeyPath)
// .merchantSerialNumber(merchantSerialNumber)
// .apiV3Key(apiV3Key)
// .build();
// return new NotificationParser(config);
// }
////
//// @Bean
//// public RefundService refundService() {
//// // 初始化商户配置
//// Config config = new RSAAutoCertificateConfig.Builder()
//// .merchantId(merchantId)
//// // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
//// .privateKeyFromPath(privateKeyPath)
//// .merchantSerialNumber(merchantSerialNumber)
//// .apiV3Key(apiV3Key)
//// .build();
//// // 初始化服务
//// return new RefundService.Builder().config(config).build();
//// }
////
//// // 分账服务
//// @Bean
//// public ProfitsharingService brandProfitSharingService() {
//// Config config = new RSAAutoCertificateConfig.Builder()
//// .merchantId(merchantId)
//// // 使用 com.wechat.pay.java.core.util中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
//// .privateKeyFromPath(privateKeyPath)
//// .merchantSerialNumber(merchantSerialNumber)
//// .apiV3Key(apiV3Key)
//// .build();
//// // 初始化服务
//// return new ProfitsharingService.Builder().config(config).build();
//// }
//
//}

View File

@ -468,4 +468,12 @@ public class ServiceConstants {
public static final String IS_AUTHENTICATION_YES = "1";
/**----------------------------是否已实名start----------------------------*/
/**----------------------------分账类型start----------------------------*/
/** 分账类型1-合伙人2-平台服务费 */
public static final String PROFITSHARING_TYPE_PARTNER = "1";
public static final String PROFITSHARING_TYPE_PLATFORM = "2";
/**----------------------------分账类型start----------------------------*/
}

View File

@ -57,6 +57,116 @@ public class SysDept extends BaseEntity
/** 运营区id */
private Long[] areaIds;
/** 平台服务费 */
private String platformServiceFee;
/** 是否开启分账 */
private String isProfitSharing;
/** appid */
private String appid;
/** appSecret */
private String appSecret;
/** merchantId */
private String merchantId;
/** apiV3Key */
private String apiV3Key;
/** 通知回调地址 */
private String notifyUrl;
/** 密钥所在位置 */
private String privateKeyPath;
/** 证书序列号 */
private String merchantSerialNumber;
/** 退款回调地址 */
private String refundNotifyUrl;
public String getPlatformServiceFee() {
return platformServiceFee;
}
public void setPlatformServiceFee(String platformServiceFee) {
this.platformServiceFee = platformServiceFee;
}
public String getIsProfitSharing() {
return isProfitSharing;
}
public void setIsProfitSharing(String isProfitSharing) {
this.isProfitSharing = isProfitSharing;
}
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getAppSecret() {
return appSecret;
}
public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}
public String getMerchantId() {
return merchantId;
}
public void setMerchantId(String merchantId) {
this.merchantId = merchantId;
}
public String getApiV3Key() {
return apiV3Key;
}
public void setApiV3Key(String apiV3Key) {
this.apiV3Key = apiV3Key;
}
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
public String getPrivateKeyPath() {
return privateKeyPath;
}
public void setPrivateKeyPath(String privateKeyPath) {
this.privateKeyPath = privateKeyPath;
}
public String getMerchantSerialNumber() {
return merchantSerialNumber;
}
public void setMerchantSerialNumber(String merchantSerialNumber) {
this.merchantSerialNumber = merchantSerialNumber;
}
public String getRefundNotifyUrl() {
return refundNotifyUrl;
}
public void setRefundNotifyUrl(String refundNotifyUrl) {
this.refundNotifyUrl = refundNotifyUrl;
}
public Long[] getAreaIds() {
return areaIds;
}

View File

@ -300,4 +300,12 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
return false;
}
}
/**
* 判断合作时间是否过期
*/
public static boolean isCooperationExpired(Date cooperationTime) {
Date currentTime = new Date();
return currentTime.after(cooperationTime);
}
}

View File

@ -17,14 +17,12 @@ public class AccessTokenUtil {
private static long tokenExpirationTime;
@SneakyThrows
public static String getToken() {
public static String getToken(String appid, String appsecret) {
if (isTokenExpired()) {
String APPID = SpringUtils.getRequiredProperty("wx.appid");
String APPSECRET = SpringUtils.getRequiredProperty("wx.appSecret");
WxMaService wxMaService = new WxMaServiceImpl();
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
config.setAppid(APPID);
config.setSecret(APPSECRET);
config.setAppid(appid);
config.setSecret(appsecret);
wxMaService.setWxMaConfig(config);
String accessToken = wxMaService.getAccessToken();
cachedToken = accessToken;

View File

@ -6,11 +6,13 @@ import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.common.utils.wx.AccessTokenUtil;
import com.ruoyi.common.utils.wx.vo.WeChatMiniAuthorizeVo;
import com.ruoyi.system.service.IAsUserService;
import com.ruoyi.system.service.IWxPayService;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
@ -66,6 +68,10 @@ public class SysLoginService
@Autowired
private IAsUserService asUserService;
@Autowired
private IWxPayService wxPayService;
/**
* 登录验证
*
@ -206,7 +212,8 @@ public class SysLoginService
AsUser user = null;
/** 根据手机号获取到用户名*/
String token = AccessTokenUtil.getToken();
SysDept dept = wxPayService.getDeptObjByAreaId(Long.parseLong(areaId));
String token = AccessTokenUtil.getToken(dept.getAppid(), dept.getAppSecret());
url = url+token;
JSONObject jsonObject = new JSONObject();
jsonObject.put("code",mobileCode);

View File

@ -140,6 +140,9 @@ public class AsDevice extends BaseEntityPlus implements Serializable {
/** 是否发送过断电指令 */
private String isAreaOutOutage;
/** 是否是管理员开锁0-否1-是(用于控制运营区外是否断电判断) */
private String isAdminUnlocking;
/** 正在进行中的订单 */
@TableField(exist = false)
private List<EtOrder> etOrders;

View File

@ -30,6 +30,10 @@ public class EtDividendDetail extends BaseEntity
@Excel(name = "合伙人id")
private Long partnerId;
/** 分账类型1-合伙人2-平台服务费 */
@Excel(name = "分账类型1-合伙人2-平台服务费")
private String type;
/** 订单号 */
@Excel(name = "订单号")
private String orderNo;

View File

@ -162,4 +162,10 @@ public class EtOperatingArea extends BaseEntityPlus implements Serializable
/** 电量低于多少值自动生成换电订单*/
private Integer autoReplacementOrder;
/** 停车点还车0-关闭1-开启*/
private String parkingReturn;
/** 运营区外还车0-关闭1-开启*/
private String areaOutReturn;
}

View File

@ -6,14 +6,14 @@ import com.ruoyi.common.core.domain.entity.SysDept;
/**
* 部门管理 数据层
*
*
* @author ruoyi
*/
public interface SysDeptMapper
{
/**
* 查询部门管理数据
*
*
* @param dept 部门信息
* @return 部门信息集合
*/
@ -21,7 +21,7 @@ public interface SysDeptMapper
/**
* 根据角色ID查询部门树信息
*
*
* @param roleId 角色ID
* @param deptCheckStrictly 部门树选择项是否关联显示
* @return 选中部门列表
@ -30,7 +30,7 @@ public interface SysDeptMapper
/**
* 根据部门ID查询信息
*
*
* @param deptId 部门ID
* @return 部门信息
*/
@ -38,7 +38,7 @@ public interface SysDeptMapper
/**
* 根据ID查询所有子部门
*
*
* @param deptId 部门ID
* @return 部门列表
*/
@ -46,7 +46,7 @@ public interface SysDeptMapper
/**
* 根据ID查询所有子部门正常状态
*
*
* @param deptId 部门ID
* @return 子部门数
*/
@ -54,7 +54,7 @@ public interface SysDeptMapper
/**
* 是否存在子节点
*
*
* @param deptId 部门ID
* @return 结果
*/
@ -62,7 +62,7 @@ public interface SysDeptMapper
/**
* 查询部门是否存在用户
*
*
* @param deptId 部门ID
* @return 结果
*/
@ -70,7 +70,7 @@ public interface SysDeptMapper
/**
* 校验部门名称是否唯一
*
*
* @param deptName 部门名称
* @param parentId 父部门ID
* @return 结果
@ -79,7 +79,7 @@ public interface SysDeptMapper
/**
* 新增部门信息
*
*
* @param dept 部门信息
* @return 结果
*/
@ -87,7 +87,7 @@ public interface SysDeptMapper
/**
* 修改部门信息
*
*
* @param dept 部门信息
* @return 结果
*/
@ -95,14 +95,14 @@ public interface SysDeptMapper
/**
* 修改所在部门正常状态
*
*
* @param deptIds 部门ID组
*/
public void updateDeptStatusNormal(Long[] deptIds);
/**
* 修改子元素关系
*
*
* @param depts 子元素
* @return 结果
*/
@ -110,9 +110,18 @@ public interface SysDeptMapper
/**
* 删除部门管理信息
*
*
* @param deptId 部门ID
* @return 结果
*/
public int deleteDeptById(Long deptId);
/**
* 根据证书序列号获取运营商
*
* @param wechatpaySerial 证书序列号
* @return 结果
*/
SysDept selectEtOperatingAreaBySerialNumber(String wechatpaySerial);
}

View File

@ -6,14 +6,14 @@ import com.ruoyi.common.core.domain.entity.SysDept;
/**
* 部门管理 服务层
*
*
* @author ruoyi
*/
public interface ISysDeptService
{
/**
* 查询部门管理数据
*
*
* @param dept 部门信息
* @return 部门信息集合
*/
@ -21,7 +21,7 @@ public interface ISysDeptService
/**
* 查询部门树结构信息
*
*
* @param dept 部门信息
* @return 部门树信息集合
*/
@ -29,7 +29,7 @@ public interface ISysDeptService
/**
* 构建前端所需要树结构
*
*
* @param depts 部门列表
* @return 树结构列表
*/
@ -37,7 +37,7 @@ public interface ISysDeptService
/**
* 构建前端所需要下拉树结构
*
*
* @param depts 部门列表
* @return 下拉树结构列表
*/
@ -45,7 +45,7 @@ public interface ISysDeptService
/**
* 根据角色ID查询部门树信息
*
*
* @param roleId 角色ID
* @return 选中部门列表
*/
@ -53,7 +53,7 @@ public interface ISysDeptService
/**
* 根据部门ID查询信息
*
*
* @param deptId 部门ID
* @return 部门信息
*/
@ -61,7 +61,7 @@ public interface ISysDeptService
/**
* 根据ID查询所有子部门正常状态
*
*
* @param deptId 部门ID
* @return 子部门数
*/
@ -69,7 +69,7 @@ public interface ISysDeptService
/**
* 是否存在部门子节点
*
*
* @param deptId 部门ID
* @return 结果
*/
@ -77,7 +77,7 @@ public interface ISysDeptService
/**
* 查询部门是否存在用户
*
*
* @param deptId 部门ID
* @return 结果 true 存在 false 不存在
*/
@ -85,7 +85,7 @@ public interface ISysDeptService
/**
* 校验部门名称是否唯一
*
*
* @param dept 部门信息
* @return 结果
*/
@ -93,14 +93,14 @@ public interface ISysDeptService
/**
* 校验部门是否有数据权限
*
*
* @param deptId 部门id
*/
public void checkDeptDataScope(Long deptId);
/**
* 新增保存部门信息
*
*
* @param dept 部门信息
* @return 结果
*/
@ -108,7 +108,7 @@ public interface ISysDeptService
/**
* 修改保存部门信息
*
*
* @param dept 部门信息
* @return 结果
*/
@ -116,9 +116,17 @@ public interface ISysDeptService
/**
* 删除部门管理信息
*
*
* @param deptId 部门ID
* @return 结果
*/
public int deleteDeptById(Long deptId);
/**
* 根据证书序列号获取运营商
*
* @param wechatpaySerial 证书序列号
* @return 结果
*/
SysDept selectEtOperatingAreaBySerialNumber(String wechatpaySerial);
}

View File

@ -1,5 +1,7 @@
package com.ruoyi.system.service;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.system.domain.EtOperatingArea;
import com.ruoyi.system.domain.EtOrder;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
@ -27,18 +29,18 @@ public interface IWxPayService {
PrepayWithRequestPaymentResponse prepayWithRequestPayment(String payType, EtOrder order);
/**
* 关闭订单
* @param billNo 平台订单编号
*/
void closeOrder(String billNo);
/**
* 通过微信订单id查询订单信息
* @param prePayId 微信订单id
* @return 订单信息
*/
Transaction queryOrderById(String prePayId);
// /**
// * 关闭订单
// * @param billNo 平台订单编号
// */
// void closeOrder(String billNo);
//
// /**
// * 通过微信订单id查询订单信息
// * @param prePayId 微信订单id
// * @return 订单信息
// */
// Transaction queryOrderById(String prePayId);
/**
* 通过商户订单号查询订单信息
@ -59,26 +61,36 @@ public interface IWxPayService {
* 根据退款单号查询退款信息
* @param outRefundNo 退款单号
*/
Refund queryByOutRefundNo(String outRefundNo);
Refund queryByOutRefundNo(Long areaId,String outRefundNo);
/**
* 根据运营区id获取运营商对象
* @param areaId 运营区id
*/
public SysDept getDeptObjByAreaId(Long areaId);
/**
* 请求分账API
* @param sysDept 运营商
* @param transactionId 微信支付单号
* @param receivers 分账接收方
*/
public OrdersEntity createOrder(String transactionId, List<CreateOrderReceiver> receivers);
public OrdersEntity createOrder(SysDept sysDept, String transactionId, List<CreateOrderReceiver> receivers);
/**
* 添加分账接收方
* @param wxopenid openid
* @param deptId 运营商id
*/
AddReceiverResponse addReceiver(String wxopenid);
AddReceiverResponse addReceiver(String wxopenid,Long deptId,String type);
/**
* 删除分账接收方
* @param wxopenid openid
* @param deptId 运营商id
*/
DeleteReceiverResponse deleteReceiver(String wxopenid);
DeleteReceiverResponse deleteReceiver(String wxopenid,Long deptId,String type);
}

View File

@ -436,58 +436,55 @@ public class AsDeviceServiceImpl extends ServiceImpl<AsDeviceMapper, AsDevice> i
/** 1.获取token*/
String token = Token.getToken();
String finalOrderNo = orderNo;
Boolean execute = transactionTemplate.execute(e -> {
/** 2.发送命令*/
ResponseVo responseVo = sendCommandWithResp(asDevice.getMac(), token, IotConstants.COMMAND_OPEN, "编号开锁");
if(responseVo.getCode() != 0){
return Boolean.FALSE;
}
/** 3.更新车辆状态*/
asDevice.setLockStatus(ServiceConstants.LOCK_STATUS_OPEN);
asDevice.setStatus(ServiceConstants.VEHICLE_STATUS_IN_USING);
int device = asDeviceMapper.updateAsDevice(asDevice);
if(device==0){
log.info("【扫码/编号开锁骑行】更新车辆状态失败");
return Boolean.FALSE;
}
/** 4.如果有预约订单则更新订单的预约结束时间,如果没有预约,则创建订单*/
EtOrder order = etOrderService.selectEtOrderByOrderNo(finalOrderNo);
if(ObjectUtil.isNotNull(order)){//有订单号可能是套餐也可能是有预约
if(ObjectUtil.isNotNull(order.getRuleId())){//套餐
log.info("【扫码/编号开锁骑行】---预约扫码骑行");
order.setSn(asDevice.getSn());
}else{
throw new ServiceException("ruleId未传");
}
order.setStatus(ServiceConstants.ORDER_STATUS_RIDING);
order.setUnlockTime(DateUtils.getNowDate());
order.setAppointmentEndTime(DateUtils.getNowDate());
//计算预约费
calculateAppointmentFee(order);
order.setTotalFee(order.getAppointmentFee());
int update = etOrderService.updateEtOrder(order);
if(update==0){
log.info("【扫码/编号开锁骑行】更新订单失败");
}
/** 2.发送命令*/
ResponseVo responseVo = sendCommandWithResp(asDevice.getMac(), token, IotConstants.COMMAND_OPEN, "编号开锁");
if(responseVo.getCode() != 0){
throw new ServiceException("【扫码/编号开锁骑行】更新车辆状态失败");
}
/** 3.更新车辆状态*/
asDevice.setLockStatus(ServiceConstants.LOCK_STATUS_OPEN);
asDevice.setStatus(ServiceConstants.VEHICLE_STATUS_IN_USING);
asDevice.setIsAdminUnlocking("0");
int device = asDeviceMapper.updateAsDevice(asDevice);
if(device==0){
log.info("【扫码/编号开锁骑行】更新车辆状态失败");
throw new ServiceException("【扫码/编号开锁骑行】更新车辆状态失败");
}
/** 4.如果有预约订单则更新订单的预约结束时间,如果没有预约,则创建订单*/
EtOrder order = etOrderService.selectEtOrderByOrderNo(finalOrderNo);
if(ObjectUtil.isNotNull(order)){//有订单号可能是套餐也可能是有预约
if(ObjectUtil.isNotNull(order.getRuleId())){//套餐
log.info("【扫码/编号开锁骑行】---预约扫码骑行");
order.setSn(asDevice.getSn());
}else{
log.info("【扫码/编号开锁骑行】---无订单号,正常开锁骑行订单");
order = etOrderService.createOrder(orderVo, finalOrderNo);
int etOrder = etOrderService.insertEtOrder(order);
if(etOrder==0){
log.info("【扫码/编号开锁骑行】保存订单失败");
return Boolean.FALSE;
}
throw new ServiceException("ruleId未传");
}
/** 5.记录行程*/
int tripLog = tripLogService.tripLog(order.getOrderNo(),order.getSn(),ServiceConstants.TRIP_LOG_TYPE_UNLOCK_RIDE);
if(tripLog==0){
log.info("【扫码/编号开锁骑行】记录行程失败");
throw new ServiceException("【扫码/编号开锁骑行】记录行程失败");
order.setStatus(ServiceConstants.ORDER_STATUS_RIDING);
order.setUnlockTime(DateUtils.getNowDate());
order.setAppointmentEndTime(DateUtils.getNowDate());
//计算预约费
calculateAppointmentFee(order);
order.setTotalFee(order.getAppointmentFee());
int update = etOrderService.updateEtOrder(order);
if(update==0){
log.info("【扫码/编号开锁骑行】更新订单失败");
}
log.info("【扫码/编号开锁骑行】车辆开锁成功");
return Boolean.TRUE;
});
if(!execute)throw new ServiceException("【扫码/编号开锁骑行】开锁失败");
}else{
log.info("【扫码/编号开锁骑行】---无订单号,正常开锁骑行订单");
order = etOrderService.createOrder(orderVo, finalOrderNo);
int etOrder = etOrderService.insertEtOrder(order);
if(etOrder==0){
log.info("【扫码/编号开锁骑行】保存订单失败");
throw new ServiceException("【扫码/编号开锁骑行】保存订单失败");
}
}
/** 5.记录行程*/
int tripLog = tripLogService.tripLog(order.getOrderNo(),order.getSn(),ServiceConstants.TRIP_LOG_TYPE_UNLOCK_RIDE);
if(tripLog==0){
log.info("【扫码/编号开锁骑行】记录行程失败");
throw new ServiceException("【扫码/编号开锁骑行】记录行程失败");
}
log.info("【扫码/编号开锁骑行】车辆开锁成功");
response.setOrderNo(orderNo);
response.setSessionId(sessionId);
return response;
@ -505,6 +502,12 @@ public class AsDeviceServiceImpl extends ServiceImpl<AsDeviceMapper, AsDevice> i
Boolean execute = transactionTemplate.execute(e -> {
/** 2.发送命令*/
sendCommand(asDevice.getMac(), token,IotConstants.COMMAND_OPEN,"管理员开锁");
asDevice.setIsAdminUnlocking("1");
asDevice.setLockStatus(ServiceConstants.LOCK_STATUS_OPEN);
int i = asDeviceMapper.updateAsDevice(asDevice);
if(i>0){
log.info("管理员开锁,更新设备状态成功");
}
return Boolean.TRUE;
});
if(!execute)throw new ServiceException("管理员开锁失败");
@ -720,6 +723,7 @@ public class AsDeviceServiceImpl extends ServiceImpl<AsDeviceMapper, AsDevice> i
/** 2.发送命令*/
sendCommand(asDevice.getMac(), Token.getToken(),IotConstants.COMMAND_CLOSE,"管理员锁车");
asDevice.setLockStatus(ServiceConstants.LOCK_STATUS_CLOSE);
asDevice.setIsAdminUnlocking("0");
int device = asDeviceMapper.updateAsDevice(asDevice);
if(device==0){
log.info("【临时解锁】改变车辆状态失败");
@ -936,6 +940,19 @@ public class AsDeviceServiceImpl extends ServiceImpl<AsDeviceMapper, AsDevice> i
if(isNoParkingArea(order.getSn(), order.getAreaId())){
throw new ServiceException("在禁停区内,不能还车");
}
// 停车点还车
EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(order.getAreaId());
if(area.getParkingReturn().equals("1")){
if(!isParkingZone(order.getSn(), order.getAreaId())){
throw new ServiceException("不在停车点内,不能还车");
}
}
// 运营区外还车
if(area.getAreaOutReturn().equals("0")){
if(!isAreaZone(order.getSn(), area)){
throw new ServiceException("在运营区外,不能还车");
}
}
/** 1. 记录还车时间*/
order.setReturnType(returnType);
order.setStatus(ServiceConstants.ORDER_STATUS_RIDING_END);

View File

@ -4,10 +4,12 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.ServiceConstants;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
@ -20,7 +22,9 @@ import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.vo.AttachVo;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.*;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.Notification;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.model.Transaction;
@ -72,9 +76,6 @@ public class CallbackServiceImpl implements CallbackService {
@Autowired
private RedisCache redisCache;
@Autowired
private NotificationParser notificationParser;
@Autowired
private IEtRefundService etRefundService;
@ -105,6 +106,12 @@ public class CallbackServiceImpl implements CallbackService {
@Autowired
private IEtDividendDetailService dividendDetailService;
@Resource
private EtAreaDeptMapper etAreaDeptMapper;
@Autowired
private ISysDeptService deptService;
@Value("${et.handlingCharge}")
private String handlingCharge;
@ -125,6 +132,8 @@ public class CallbackServiceImpl implements CallbackService {
// 支付成功通知
if (NotifyEventType.TRANSACTION_SUCCESS.getValue().equals(notification.getEventType())) {
// 验签解密并转换成 Transaction
String wechatpaySerial = request.getHeader("Wechatpay-Serial");
logger.info("证书序列号:" + wechatpaySerial);
Transaction transaction = checkAndParse(request, body, Transaction.class);
if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
// 充值成功后的业务处理
@ -246,59 +255,114 @@ public class CallbackServiceImpl implements CallbackService {
sysUser.setAreaId(area.getAreaId());
List<SysUser> sysUsers = userMapper.selectUserList(sysUser);
for (SysUser sysUser1 : sysUsers){
EtDividendDetail etDividendDetail = new EtDividendDetail();
AsUser asUser1 = asUserMapper.selectUserById(sysUser1.getAppUserId());
if(asUser1!=null && asUser1.getWxopenid()!=null){
BigDecimal dividendAmount = BigDecimal.ZERO;
logger.info("=============系统用户sysUser1============"+JSON.toJSONString(sysUser1));
CreateOrderReceiver receiver = new CreateOrderReceiver();
receiver.setType(ReceiverType.PERSONAL_OPENID.name());
receiver.setAccount(asUser1.getWxopenid());
String dividendItem = sysUser1.getDividendItem();
logger.info("=================分账项目dividendItem=================="+dividendItem);
if(dividendItem.contains("1")){
logger.info("=================骑行费(骑行费+预约费)==================");
dividendAmount = dividendAmount.add(order.getRidingFee().add(order.getAppointmentFee()));//1-骑行费骑行费+预约费
}
if(dividendItem.contains("2")){
logger.info("=================调度费(调度费+管理费)==================");
dividendAmount = dividendAmount.add(order.getManageFee().add(order.getDispatchFee()));//2-调度费调度费+管理费
}
logger.info("=================分账金额dividendAmount=================="+dividendAmount);
BigDecimal divide = new BigDecimal(sysUser1.getDividendProportion()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
logger.info("=================分账比例%=================="+divide);
BigDecimal multiply = dividendAmount.multiply(divide);
logger.info(sysUser1.getUserName()+"分账比例:"+sysUser1.getDividendProportion()+"%,分账金额:"+multiply);
receiver.setAmount(multiply.multiply(new BigDecimal(100)).longValue());
receiver.setDescription(area.getAreaName()+"共享电动车自动分账");
receivers.add(receiver);
if(ObjectUtil.isNotNull(sysUsers) && sysUsers.size()>0){
for (SysUser sysUser1 : sysUsers){
// 判断是否过合作时间是否禁用
boolean cooperationExpired = DateUtils.isCooperationExpired(sysUser1.getCooperationTime());
if(!cooperationExpired && sysUser1.getStatus().equals("0")){
EtDividendDetail etDividendDetail = new EtDividendDetail();
AsUser asUser1 = asUserMapper.selectUserById(sysUser1.getAppUserId());
if(asUser1!=null && asUser1.getWxopenid()!=null){
BigDecimal dividendAmount = BigDecimal.ZERO;
logger.info("=============系统用户sysUser1============"+JSON.toJSONString(sysUser1));
CreateOrderReceiver receiver = new CreateOrderReceiver();
receiver.setType(ReceiverType.PERSONAL_OPENID.name());
receiver.setAccount(asUser1.getWxopenid());
String dividendItem = sysUser1.getDividendItem();
logger.info("=================分账项目dividendItem=================="+dividendItem);
if(dividendItem.contains("1")){
logger.info("=================骑行费(骑行费+预约费)==================");
dividendAmount = dividendAmount.add(order.getRidingFee().add(order.getAppointmentFee()));//1-骑行费骑行费+预约费
}
if(dividendItem.contains("2")){
logger.info("=================调度费(调度费+管理费)==================");
dividendAmount = dividendAmount.add(order.getManageFee().add(order.getDispatchFee()));//2-调度费调度费+管理费
}
logger.info("=================分账金额dividendAmount=================="+dividendAmount);
BigDecimal divide = new BigDecimal(sysUser1.getDividendProportion()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
logger.info("=================分账比例%=================="+divide);
BigDecimal multiply = dividendAmount.multiply(divide);
logger.info(sysUser1.getUserName()+"分账比例:"+sysUser1.getDividendProportion()+"%,分账金额:"+multiply);
receiver.setAmount(multiply.multiply(new BigDecimal(100)).longValue());
receiver.setDescription(area.getAreaName()+"共享电动车自动分账");
receivers.add(receiver);
etDividendDetail.setAreaId(area.getAreaId());
etDividendDetail.setPartnerId(sysUser1.getUserId());
etDividendDetail.setOrderNo(order.getOrderNo());
etDividendDetail.setTotalAmount(order.getTotalFee());
etDividendDetail.setCreateTime(DateUtils.getNowDate());
etDividendDetail.setDividendProportion(sysUser1.getDividendProportion());
etDividendDetail.setDividendAmount(multiply);
etDividendDetail.setDividendItem(dividendItem);
logger.info("【微信支付回调】保存分账明细 === " + JSON.toJSONString(etDividendDetail));
int i = dividendDetailService.insertEtDividendDetail(etDividendDetail);
if(i==0){
throw new ServiceException("保存分账明细失败");
etDividendDetail.setAreaId(area.getAreaId());
etDividendDetail.setType(ServiceConstants.PROFITSHARING_TYPE_PARTNER);
etDividendDetail.setPartnerId(sysUser1.getUserId());
etDividendDetail.setOrderNo(order.getOrderNo());
etDividendDetail.setTotalAmount(order.getTotalFee());
etDividendDetail.setCreateTime(DateUtils.getNowDate());
etDividendDetail.setDividendProportion(sysUser1.getDividendProportion());
etDividendDetail.setDividendAmount(multiply);
etDividendDetail.setDividendItem(dividendItem);
logger.info("【微信支付回调】保存分账明细 === " + JSON.toJSONString(etDividendDetail));
int i = dividendDetailService.insertEtDividendDetail(etDividendDetail);
if(i==0){
throw new ServiceException("保存分账明细失败");
}
}
}else{
logger.info("=================【微信支付回调】合伙人【{}】已禁用或已过期合作期==================",sysUser1.getUserName());
}
}
}
OrdersEntity ordersEntity = wxPayService.createOrder(transactionId,receivers);
if(ordersEntity!=null){
logger.info("【微信支付回调】发起分账响应:【{}】",JSON.toJSON(ordersEntity));
// 计算平台服务费
logger.info("=================【微信支付回调】计算平台服务费==================");
platformServiceFee(order, area, receivers);
List<EtAreaDept> areaId1 = etAreaDeptMapper.selectList(new QueryWrapper<EtAreaDept>().eq("area_id", order.getAreaId()));
if (ObjectUtil.isNotEmpty(areaId1) && areaId1.size() > 0){
EtAreaDept etAreaDept = areaId1.get(0);
SysDept sysDept = deptService.selectDeptById(etAreaDept.getDeptId());
logger.info("获取到运营商对象:【{}】",JSON.toJSON(sysDept));
OrdersEntity ordersEntity = wxPayService.createOrder(sysDept,transactionId,receivers);
if(ordersEntity!=null){
logger.info("【微信支付回调】发起分账响应:【{}】",JSON.toJSON(ordersEntity));
}else{
logger.info("【微信支付回调】发起分账失败");
throw new ServiceException("发起分账失败");
}
}else{
logger.info("【微信支付回调】发起分账失败");
throw new ServiceException("发起分账失败");
logger.info("区域:【{}】没有绑定运营商",order.getAreaId());
throw new ServiceException("区域:【"+order.getAreaId()+"】没有绑定运营商");
}
return false;
}
/**
* 计算平台服务费
*/
private void platformServiceFee(EtOrder order, EtOperatingArea area, List<CreateOrderReceiver> receivers) {
CreateOrderReceiver receiver = new CreateOrderReceiver();
SysDept cxPlatform = deptService.selectDeptById(100L);//创享电动车
receiver.setType(ReceiverType.MERCHANT_ID.name());
receiver.setAccount(cxPlatform.getMerchantId());
receiver.setDescription("平台服务费");
BigDecimal divide = new BigDecimal(cxPlatform.getPlatformServiceFee()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
BigDecimal platformServiceFee = order.getTotalFee().multiply(divide);
logger.info("平台服务费比例:"+cxPlatform.getPlatformServiceFee()+"%,分账金额:"+platformServiceFee);
receiver.setAmount(platformServiceFee.longValue());//平台服务费 = 平台服务费比例 * 订单金额
receivers.add(receiver);
EtDividendDetail etDividendDetail = new EtDividendDetail();
etDividendDetail.setAreaId(area.getAreaId());
etDividendDetail.setType("2");
etDividendDetail.setOrderNo(order.getOrderNo());
etDividendDetail.setType(ServiceConstants.PROFITSHARING_TYPE_PLATFORM);
etDividendDetail.setTotalAmount(order.getTotalFee());
etDividendDetail.setCreateTime(DateUtils.getNowDate());
etDividendDetail.setDividendProportion(Integer.parseInt(cxPlatform.getPlatformServiceFee()));
etDividendDetail.setDividendAmount(platformServiceFee);
etDividendDetail.setDividendItem("1,2");
logger.info("【微信支付回调】平台服务费的分账明细保存 === " + JSON.toJSONString(etDividendDetail));
int i = dividendDetailService.insertEtDividendDetail(etDividendDetail);
if(i==0){
throw new ServiceException("保存分账明细失败");
}
}
/**
* 退还押金定时任务
*/
@ -468,7 +532,25 @@ public class CallbackServiceImpl implements CallbackService {
.body(body)
.build();
// 验签
String wechatpaySerial = request.getHeader("Wechatpay-Serial");
NotificationParser notificationParser = getNotificationParser(wechatpaySerial);
return notificationParser.parse(requestParam, clazz);
}
public NotificationParser getNotificationParser(String wechatpaySerial) {
// 根据证书序列号获取运营商
SysDept sysDept = deptService.selectEtOperatingAreaBySerialNumber(wechatpaySerial);
if(ObjectUtil.isNull(sysDept)){
throw new ServiceException("【微信支付回调】根据证书序列号获取运营商失败");
}else{
NotificationConfig config = new RSAAutoCertificateConfig.Builder()
.merchantId(sysDept.getMerchantId())
.privateKeyFromPath(sysDept.getPrivateKeyPath())
.merchantSerialNumber(sysDept.getMerchantSerialNumber())
.apiV3Key(sysDept.getApiV3Key())
.build();
return new NotificationParser(config);
}
}
}

View File

@ -1,6 +1,8 @@
package com.ruoyi.system.service.impl;
import java.util.List;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.service.IAsUserService;
import org.springframework.beans.factory.annotation.Autowired;
@ -40,6 +42,7 @@ public class EtFeeRuleServiceImpl implements IEtFeeRuleService
* @return 收费方式
*/
@Override
@DataScope(deptAlias = "d")
public List<EtFeeRule> selectEtFeeRuleList(EtFeeRule etFeeRule)
{
return etFeeRuleMapper.selectEtFeeRuleList(etFeeRule);

View File

@ -5,6 +5,7 @@ import java.util.List;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.constant.IotConstants;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.common.core.domain.entity.SysDept;
@ -75,6 +76,7 @@ public class EtModelServiceImpl implements IEtModelService
* @return 车辆型号
*/
@Override
@DataScope(deptAlias = "d")
public List<EtModel> selectEtModelList(EtModel etModel)
{
List<EtModel> etModels = etModelMapper.selectEtModelList(etModel);

View File

@ -3,6 +3,7 @@ package com.ruoyi.system.service.impl;
import java.util.List;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@ -251,11 +252,14 @@ public class EtOperatingAreaServiceImpl extends ServiceImpl<EtOperatingAreaMappe
List<EtOperatingArea> etOperatingAreas = etOperatingAreaService.selectEtOperatingAreaList(new EtOperatingArea());
EtOperatingArea area = null;
for(EtOperatingArea etOperatingArea:etOperatingAreas){
Geometry geometry = GeoUtils.fromWkt(etOperatingArea.getBoundary());
Boolean inCircle = GeoUtils.isInCircle(longitude, latitude, geometry);
if(inCircle){
area = etOperatingArea;
break;
String boundary = etOperatingArea.getBoundary();
if(StrUtil.isNotBlank(boundary)){
Geometry geometry = GeoUtils.fromWkt(boundary);
Boolean inCircle = GeoUtils.isInCircle(longitude, latitude, geometry);
if(inCircle){
area = etOperatingArea;
break;
}
}
}
if(ObjectUtil.isNotNull(area)){

View File

@ -1,8 +1,11 @@
package com.ruoyi.system.service.impl;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.constant.ServiceConstants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
@ -17,6 +20,9 @@ import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.IWxPayService;
import com.wechat.pay.java.service.profitsharing.model.AddReceiverResponse;
import com.wechat.pay.java.service.profitsharing.model.DeleteReceiverResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -55,6 +61,9 @@ public class SysDeptServiceImpl implements ISysDeptService
@Autowired
private SysUserRoleMapper userRoleMapper;
@Autowired
private IWxPayService wxPayService;
/**
* 查询部门管理数据
*
@ -241,11 +250,18 @@ public class SysDeptServiceImpl implements ISysDeptService
dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
int i = deptMapper.insertDept(dept);
Long[] areaIds = dept.getAreaIds();
for (Long areaId:areaIds){
etAreaDeptMapper.insert(EtAreaDept.builder().areaId(areaId).deptId(dept.getDeptId()).build());
if (StringUtils.isNotNull(areaIds)){
for (Long areaId:areaIds){
etAreaDeptMapper.insert(EtAreaDept.builder().areaId(areaId).deptId(dept.getDeptId()).build());
}
}
// 添加运营商账号并添加运营商角色
createOperator(dept);
// 是否分账
if("true".equals(dept.getIsProfitSharing()) && StringUtils.isNotEmpty(dept.getMerchantId()) && dept.getParentId() != 0L){
AddReceiverResponse addReceiverResponse = wxPayService.addReceiver(dept.getMerchantId(),dept.getDeptId(), ServiceConstants.PROFITSHARING_TYPE_PLATFORM);
log.info("添加分账接收方响应:【{}】", JSON.toJSON(addReceiverResponse));
}
return i;
}
@ -277,11 +293,21 @@ public class SysDeptServiceImpl implements ISysDeptService
}
etAreaDeptMapper.deleteAreaDeptByDeptId(dept.getDeptId());
Long[] areaIds = dept.getAreaIds();
for (Long areaId:areaIds){
etAreaDeptMapper.insert(EtAreaDept.builder().areaId(areaId).deptId(dept.getDeptId()).build());
if (StringUtils.isNotNull(areaIds)){
for (Long areaId:areaIds){
etAreaDeptMapper.insert(EtAreaDept.builder().areaId(areaId).deptId(dept.getDeptId()).build());
}
}
// 添加运营商账号并添加运营商角色
createOperator(dept);
// createOperator(dept);
if("true".equals(dept.getIsProfitSharing()) && StringUtils.isNotEmpty(dept.getMerchantId()) && dept.getParentId() != 0L){
// 删除分账接收方
DeleteReceiverResponse deleteReceiverResponse = wxPayService.deleteReceiver(dept.getMerchantId(),dept.getDeptId(),ServiceConstants.PROFITSHARING_TYPE_PLATFORM);
log.info("删除分账接收方响应:【{}】", JSON.toJSON(deleteReceiverResponse));
AddReceiverResponse addReceiverResponse = wxPayService.addReceiver(dept.getMerchantId(),dept.getDeptId(), ServiceConstants.PROFITSHARING_TYPE_PLATFORM);
log.info("添加分账接收方响应:【{}】", JSON.toJSON(addReceiverResponse));
}
return result;
}
@ -295,7 +321,7 @@ public class SysDeptServiceImpl implements ISysDeptService
SysUser sysUser = new SysUser();
sysUser.setDeptId(dept.getDeptId());
sysUser.setUserName(dept.getPhone());
sysUser.setNickName(dept.getLeader());
sysUser.setNickName(dept.getPhone());
sysUser.setPhonenumber(dept.getPhone());
sysUser.setUserType("00");
String password = configService.selectConfigByKey("sys.user.initPassword");
@ -368,6 +394,18 @@ public class SysDeptServiceImpl implements ISysDeptService
return deptMapper.deleteDeptById(deptId);
}
/**
* 根据证书序列号获取运营商
*
* @param wechatpaySerial 证书序列号
* @return 结果
*/
@Override
public SysDept selectEtOperatingAreaBySerialNumber(String wechatpaySerial) {
SysDept sysDept = deptMapper.selectEtOperatingAreaBySerialNumber(wechatpaySerial);
return sysDept;
}
/**
* 递归列表
*/

View File

@ -5,6 +5,7 @@ import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.constant.ServiceConstants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.common.core.domain.entity.SysRole;
@ -399,7 +400,7 @@ public class SysUserServiceImpl implements ISysUserService
AsUser asUser = asUserService.selectUserByPhone(user.getPhonenumber());
if(ObjectUtils.isNotEmpty(asUser)){
// 删除分账接收方
deleteReceiver(asUser.getWxopenid());
deleteReceiver(asUser.getWxopenid(),user.getDeptId());
// 添加分账接收方
addReceiver(user,asUser);
}else{
@ -420,7 +421,7 @@ public class SysUserServiceImpl implements ISysUserService
// 绑定app用户
userMapper.bandAppUser(asUser.getUserId(), user.getUserId());
// 添加分账接收方
AddReceiverResponse addReceiverResponse = wxPayService.addReceiver(asUser.getWxopenid());
AddReceiverResponse addReceiverResponse = wxPayService.addReceiver(asUser.getWxopenid(),SecurityUtils.getLoginUser().getUser().getDeptId(), ServiceConstants.PROFITSHARING_TYPE_PARTNER);
log.info("添加分账接收方响应:【{}】", JSON.toJSON(addReceiverResponse));
}
@ -429,9 +430,9 @@ public class SysUserServiceImpl implements ISysUserService
*
* @param openid
*/
private void deleteReceiver(String openid) {
private void deleteReceiver(String openid,Long deptId) {
// 添加分账接收方
DeleteReceiverResponse deleteReceiverResponse = wxPayService.deleteReceiver(openid);
DeleteReceiverResponse deleteReceiverResponse = wxPayService.deleteReceiver(openid,deptId,ServiceConstants.PROFITSHARING_TYPE_PARTNER);
log.info("删除分账接收方响应:【{}】", JSON.toJSON(deleteReceiverResponse));
}
@ -588,7 +589,7 @@ public class SysUserServiceImpl implements ISysUserService
SysUser user = selectUserById(userId);
AsUser asUser = asUserService.selectUserByPhone(user.getPhonenumber());
// 删除分账接收方
deleteReceiver(asUser.getWxopenid());
deleteReceiver(asUser.getWxopenid(),user.getDeptId());
return userMapper.deleteUserById(userId);
}

View File

@ -1,22 +1,27 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.config.WxPayConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.constant.ServiceConstants;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.core.redis.RedisLock;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.system.domain.EtAreaDept;
import com.ruoyi.system.domain.EtOperatingArea;
import com.ruoyi.system.domain.EtOrder;
import com.ruoyi.system.domain.vo.AttachVo;
import com.ruoyi.system.mapper.EtAreaDeptMapper;
import com.ruoyi.system.service.IAsUserService;
import com.ruoyi.system.service.IEtOperatingAreaService;
import com.ruoyi.system.service.IEtOrderService;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.IWxPayService;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
@ -32,14 +37,11 @@ import com.wechat.pay.java.service.refund.model.QueryByOutRefundNoRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import javax.management.relation.RelationType;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
@ -51,17 +53,11 @@ import java.util.List;
@Slf4j
public class WxPayService implements IWxPayService {
@Autowired
private JsapiService jsapiService;
// @Autowired
// private JsapiService jsapiService;
@Autowired
private JsapiServiceExtension jsapiServiceExtension;
@Autowired
private WxPayConfig wxPayConfig;
@Autowired
private IEtOperatingAreaService etOperatingAreaService;
// @Autowired
// private JsapiServiceExtension jsapiServiceExtension;
@Autowired
private IEtOrderService etOrderService;
@ -69,23 +65,23 @@ public class WxPayService implements IWxPayService {
@Autowired
private IAsUserService asUserService;
@Autowired
private NotificationParser notificationParser;
// @Autowired
// private NotificationParser notificationParser;
@Autowired
private TransactionTemplate transactionTemplate;
// @Autowired
// public RefundService refundService2;
@Autowired
public RefundService refundService2;
@Autowired
public ProfitsharingService profitsharingService;
// @Autowired
// public ProfitsharingService profitsharingService;
@Autowired
private RedisLock redisLock;
@Value("${et.profitSharing}")
private Boolean profitSharing;
@Resource
private EtAreaDeptMapper etAreaDeptMapper;
@Autowired
private ISysDeptService deptService;
private static final String CNY = "CNY";
@ -97,54 +93,66 @@ public class WxPayService implements IWxPayService {
// 创建订单
AsUser user = asUserService.selectUserById(order.getUserId());
try {
// 获取JSAPI所需参数
PrepayRequest request = new PrepayRequest();
request.setAmount(getAmount(order.getTotalFee()));
String outTradeNo = IdUtils.getOrderNo("wx");
order.setOutTradeNo(outTradeNo);
int updateEtOrder = etOrderService.updateEtOrder(order);
if(updateEtOrder == 0){
throw new ServiceException("更新订单outTradeNo失败");
List<EtAreaDept> areaId1 = etAreaDeptMapper.selectList(new QueryWrapper<EtAreaDept>().eq("area_id", order.getAreaId()));
if (ObjectUtil.isNotEmpty(areaId1) && areaId1.size() > 0){
EtAreaDept etAreaDept = areaId1.get(0);
SysDept sysDept = deptService.selectDeptById(etAreaDept.getDeptId());
log.info("获取到运营商对象:【{}】",JSON.toJSON(sysDept));
if(ObjectUtil.isNull(sysDept)){
throw new ServiceException("没有运营商:【"+etAreaDept.getDeptId()+"");
}
String isProfitSharing = sysDept.getIsProfitSharing();
// 获取JSAPI所需参数
PrepayRequest request = new PrepayRequest();
request.setAmount(getAmount(order.getTotalFee()));
String outTradeNo = IdUtils.getOrderNo("wx");
order.setOutTradeNo(outTradeNo);
int updateEtOrder = etOrderService.updateEtOrder(order);
if(updateEtOrder == 0){
throw new ServiceException("更新订单outTradeNo失败");
}
request.setOutTradeNo(outTradeNo);
request.setAppid(sysDept.getAppid());
request.setMchid(sysDept.getMerchantId());
String type = order.getType();
String description = type.equals(ServiceConstants.ORDER_TYPE_RIDING) ? "骑行订单-"+billNo : "押金充值-"+billNo;
LoginUser loginUser = SecurityUtils.getLoginUser();
log.info("【预下单】获取登录用户信息:"+JSON.toJSONString(loginUser));
request.setAttach(JSON.toJSONString(new AttachVo(payType,user.getUserId(), loginUser.getToken())));
request.setDescription(description);
request.setNotifyUrl(sysDept.getNotifyUrl());
request.setPayer(getPayer(user.getWxopenid()));
SettleInfo settleInfo = new SettleInfo();
settleInfo.setProfitSharing( "true".equalsIgnoreCase(isProfitSharing));
request.setSettleInfo(settleInfo);
JsapiServiceExtension jsapiServiceExtension = getJsapiServiceExtension(sysDept);
PrepayWithRequestPaymentResponse res = jsapiServiceExtension.prepayWithRequestPayment(request);
return res;
}else{
log.info("区域:【{}】没有绑定运营商",order.getAreaId());
throw new ServiceException("区域:【"+order.getAreaId()+"】没有绑定运营商");
}
request.setOutTradeNo(outTradeNo);
request.setAppid(wxPayConfig.getAppId());
request.setMchid(wxPayConfig.getMerchantId());
String type = order.getType();
String description = type.equals(ServiceConstants.ORDER_TYPE_RIDING) ? "骑行订单-"+billNo : "押金充值-"+billNo;
LoginUser loginUser = SecurityUtils.getLoginUser();
log.info("【预下单】获取登录用户信息:"+JSON.toJSONString(loginUser));
request.setAttach(JSON.toJSONString(new AttachVo(payType,user.getUserId(), loginUser.getToken())));
request.setDescription(description);
request.setNotifyUrl(wxPayConfig.getNotifyUrl());
request.setPayer(getPayer(user.getWxopenid()));
SettleInfo settleInfo = new SettleInfo();
settleInfo.setProfitSharing(profitSharing);
request.setSettleInfo(settleInfo);
PrepayWithRequestPaymentResponse res = jsapiServiceExtension.prepayWithRequestPayment(request);
return res;
} finally {
redisLock.unlock(PREPAY_LOCK + billNo);
}
}
/**
* 关闭支付订单
* @param billNo 平台订单编号
*/
@Override
public void closeOrder(String billNo) {
CloseOrderRequest request = new CloseOrderRequest();
request.setMchid(wxPayConfig.getMerchantId());
request.setOutTradeNo(billNo);
jsapiService.closeOrder(request);
}
@Override
public Transaction queryOrderById(String prePayId) {
QueryOrderByIdRequest request = new QueryOrderByIdRequest();
request.setMchid(wxPayConfig.getMerchantId());
request.setTransactionId(prePayId);
return jsapiService.queryOrderById(request);
private JsapiServiceExtension getJsapiServiceExtension(SysDept sysDept) {
// 初始化商户配置
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(sysDept.getMerchantId())
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
.privateKeyFromPath(sysDept.getPrivateKeyPath())
.merchantSerialNumber(sysDept.getMerchantSerialNumber())
.apiV3Key(sysDept.getApiV3Key())
.build();
// 初始化服务
return new JsapiServiceExtension
.Builder()
.config(config)
.signType("RSA") // 不填默认为RSA
.build();
}
/**
@ -154,10 +162,34 @@ public class WxPayService implements IWxPayService {
*/
@Override
public Transaction queryOrderByOutTradeNo(String outTradeNo) {
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
request.setMchid(wxPayConfig.getMerchantId());
request.setOutTradeNo(outTradeNo);
return jsapiService.queryOrderByOutTradeNo(request);
EtOrder order = etOrderService.selectEtOrderByOutTradeNo(outTradeNo);
List<EtAreaDept> areaId1 = etAreaDeptMapper.selectList(new QueryWrapper<EtAreaDept>().eq("area_id", order.getAreaId()));
if (ObjectUtil.isNotEmpty(areaId1) && areaId1.size() > 0){
EtAreaDept etAreaDept = areaId1.get(0);
SysDept sysDept = deptService.selectDeptById(etAreaDept.getDeptId());
log.info("获取到运营商对象:【{}】",JSON.toJSON(sysDept));
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
request.setMchid(sysDept.getMerchantId());
request.setOutTradeNo(outTradeNo);
JsapiService jsapiService = getJsapiService(sysDept);
return jsapiService.queryOrderByOutTradeNo(request);
}else{
log.info("区域:【{}】没有绑定运营商",order.getAreaId());
throw new ServiceException("区域:【"+order.getAreaId()+"】没有绑定运营商");
}
}
private JsapiService getJsapiService(SysDept sysDept) {
// 初始化商户配置
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(sysDept.getMerchantId())
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
.privateKeyFromPath(sysDept.getPrivateKeyPath())
.merchantSerialNumber(sysDept.getMerchantSerialNumber())
.apiV3Key(sysDept.getApiV3Key())
.build();
// 初始化服务
return new JsapiService.Builder().config(config).build();
}
/**
@ -168,76 +200,138 @@ public class WxPayService implements IWxPayService {
*/
@Override
public Refund refund(EtOrder etOrder,String reason,BigDecimal amount) {
SysDept sysDept = getDeptObjByAreaId(etOrder.getAreaId());
CreateRequest request = new CreateRequest();
request.setOutTradeNo(etOrder.getOutTradeNo());
request.setOutRefundNo(IdUtils.getOrderNo("ref"));
request.setReason(reason);
request.setAmount(getAmountReq(etOrder.getTotalFee(),amount));
request.setNotifyUrl(wxPayConfig.getRefundNotifyUrl());
request.setNotifyUrl(sysDept.getRefundNotifyUrl());
log.info("【退款】请求微信参数:【{}】",JSON.toJSONString(request));
Refund refund = refundService2.create(request);
RefundService refundService = getRefundService(sysDept);
Refund refund = refundService.create(request);
log.info("【退款】微信返回结果:【{}】",JSON.toJSONString(refund));
return refund;
}
private RefundService getRefundService(SysDept sysDept){
// 初始化商户配置
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(sysDept.getMerchantId())
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
.privateKeyFromPath(sysDept.getPrivateKeyPath())
.merchantSerialNumber(sysDept.getMerchantSerialNumber())
.apiV3Key(sysDept.getApiV3Key())
.build();
// 初始化服务
return new RefundService.Builder().config(config).build();
}
/**
* 根据运营区id获取运营商对象
* @param areaId
* @return
*/
@Override
public Refund queryByOutRefundNo(String outRefundNo) {
public SysDept getDeptObjByAreaId(Long areaId) {
SysDept sysDept;
List<EtAreaDept> areaId1 = etAreaDeptMapper.selectList(new QueryWrapper<EtAreaDept>().eq("area_id", areaId));
if (ObjectUtil.isNotEmpty(areaId1) && areaId1.size() > 0){
EtAreaDept etAreaDept = areaId1.get(0);
sysDept = deptService.selectDeptById(etAreaDept.getDeptId());
log.info("获取到运营商对象:【{}】",JSON.toJSON(sysDept));
}else{
log.info("区域:【{}】没有绑定运营商",areaId);
throw new ServiceException("区域:【"+areaId+"】没有绑定运营商");
}
return sysDept;
}
@Override
public Refund queryByOutRefundNo(Long areaId,String outRefundNo) {
SysDept sysDept = getDeptObjByAreaId(areaId);
QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
request.setOutRefundNo(outRefundNo);
return refundService2.queryByOutRefundNo(request);
RefundService refundService = getRefundService(sysDept);
return refundService.queryByOutRefundNo(request);
}
/** 请求分账API */
public OrdersEntity createOrder(String transactionId,List<CreateOrderReceiver> receivers) {
public OrdersEntity createOrder(SysDept sysDept,String transactionId,List<CreateOrderReceiver> receivers) {
CreateOrderRequest request = new CreateOrderRequest();
request.setAppid(wxPayConfig.getAppId());
request.setAppid(sysDept.getAppid());
request.setTransactionId(transactionId);// 微信订单号
request.setOutOrderNo(IdUtils.getOrderNo("fz"));// 商户系统内部分账单号
request.setReceivers(receivers);
request.setUnfreezeUnsplit(true);
ProfitsharingService profitsharingService = getProfitsharingService(sysDept);
return profitsharingService.createOrder(request);
}
/** 添加分账接收方 */
@Override
public AddReceiverResponse addReceiver(String wxopenid) {
public AddReceiverResponse addReceiver(String wxopenid,Long deptId,String type) {
SysDept sysDept = deptService.selectDeptById(deptId);
AddReceiverRequest request = new AddReceiverRequest();
request.setAppid(wxPayConfig.getAppId());
request.setType(ReceiverType.PERSONAL_OPENID);
request.setAppid(sysDept.getAppid());
if(type.equals(ServiceConstants.PROFITSHARING_TYPE_PLATFORM)){
request.setType(ReceiverType.MERCHANT_ID);
}else{
request.setType(ReceiverType.PERSONAL_OPENID);
}
request.setAccount(wxopenid);
request.setRelationType(ReceiverRelationType.PARTNER);
ProfitsharingService profitsharingService = getProfitsharingService(sysDept);
return profitsharingService.addReceiver(request);
}
/** 删除分账接收方 */
public DeleteReceiverResponse deleteReceiver(String wxopenid) {
public DeleteReceiverResponse deleteReceiver(String wxopenid,Long deptId,String type) {
SysDept sysDept = deptService.selectDeptById(deptId);
DeleteReceiverRequest request = new DeleteReceiverRequest();
request.setAppid(wxPayConfig.getAppId());
request.setType(ReceiverType.PERSONAL_OPENID);
request.setAppid(sysDept.getAppid());
if(type.equals(ServiceConstants.PROFITSHARING_TYPE_PLATFORM)){
request.setType(ReceiverType.MERCHANT_ID);
}else{
request.setType(ReceiverType.PERSONAL_OPENID);
}
request.setAccount(wxopenid);
ProfitsharingService profitsharingService = getProfitsharingService(sysDept);
return profitsharingService.deleteReceiver(request);
}
/**
* 验签并解析
* @param request 请求
* @param body 请求体
* @param clazz 返回值类型
*/
private <T> T checkAndParse(HttpServletRequest request, String body, Class<T> clazz) {
// 构造 RequestParam
RequestParam requestParam = new RequestParam.Builder()
.serialNumber(request.getHeader("Wechatpay-Serial"))
.nonce(request.getHeader("Wechatpay-Nonce"))
.signature(request.getHeader("Wechatpay-Signature"))
.timestamp(request.getHeader("Wechatpay-Timestamp"))
.body(body)
.build();
// 验签
return notificationParser.parse(requestParam, clazz);
private ProfitsharingService getProfitsharingService(SysDept sysDept) {
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(sysDept.getMerchantId())
// 使用 com.wechat.pay.java.core.util中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名
.privateKeyFromPath(sysDept.getPrivateKeyPath())
.merchantSerialNumber(sysDept.getMerchantSerialNumber())
.apiV3Key(sysDept.getApiV3Key())
.build();
// 初始化服务
return new ProfitsharingService.Builder().config(config).build();
}
// /**
// * 验签并解析
// * @param request 请求
// * @param body 请求体
// * @param clazz 返回值类型
// */
// private <T> T checkAndParse(HttpServletRequest request, String body, Class<T> clazz) {
// // 构造 RequestParam
// RequestParam requestParam = new RequestParam.Builder()
// .serialNumber(request.getHeader("Wechatpay-Serial"))
// .nonce(request.getHeader("Wechatpay-Nonce"))
// .signature(request.getHeader("Wechatpay-Signature"))
// .timestamp(request.getHeader("Wechatpay-Timestamp"))
// .body(body)
// .build();
// // 验签
// return notificationParser.parse(requestParam, clazz);
// }
private Payer getPayer(String openId) {
Payer payer = new Payer();
payer.setOpenid(openId);

View File

@ -153,7 +153,7 @@ public class EtTask {
if(!Constants.SUCCESS2.equals(etRefund.getRefundResult())){
log.info("【系统启动】押金退款未成功回调,退款单号:【{}】",etRefund.getRefundNo());
// 根据退款单号查询退款信息
Refund refund = wxPayService.queryByOutRefundNo(etRefund.getRefundNo());
Refund refund = wxPayService.queryByOutRefundNo(area.getAreaId(),etRefund.getRefundNo());
if(ObjectUtil.isNotNull(refund) && Constants.SUCCESS2.equals(refund.getStatus().name())){
// 更新退款记录
etRefund.setRefundResult(Constants.SUCCESS2);

View File

@ -30,17 +30,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="longitude" column="longitude" />
<result property="latitude" column="latitude" />
<result property="isAreaOutOutage" column="is_area_out_outage" />
<result property="isAdminUnlocking" column="is_admin_unlocking" />
</resultMap>
<sql id="selectAsDeviceVo">
select device_id, picture, device_name, mac, sn, model_id, vehicle_num, area_id, activation_time, online_status, create_by, create_time, update_by, update_time, last_time, remark, status, lock_status, location, remaining_power, voltage, qrcode, longitude, latitude, is_area_out_outage from et_device
select device_id, picture, device_name, mac, sn, model_id, vehicle_num, area_id, activation_time, online_status, create_by, create_time, update_by, update_time, last_time, remark, status, lock_status, location, remaining_power, voltage, qrcode, longitude, latitude, is_area_out_outage, is_admin_unlocking from et_device
</sql>
<select id="selectAsDeviceList" parameterType="AsDevice" resultMap="AsDeviceResult">
select de.device_id, de.picture, de.device_name, de.mac, de.sn, de.model_id, de.vehicle_num, de.area_id,
de.activation_time, de.online_status, de.create_by, de.create_time, de.update_by,
de.update_time, de.last_time, de.remark, de.status, de.lock_status, de.location,
de.remaining_power, de.voltage, de.qrcode, de.longitude, de.latitude, de.is_area_out_outage from et_device de
de.remaining_power, de.voltage, de.qrcode, de.longitude, de.latitude, de.is_area_out_outage, de.is_admin_unlocking from et_device de
left join et_area_dept ad on ad.area_id = de.area_id
left join sys_dept d on d.dept_id = ad.dept_id
where 1 = 1
@ -61,7 +62,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select de.device_id, de.picture, de.device_name, de.mac, de.sn, de.model_id, de.vehicle_num, de.area_id,
de.activation_time, de.online_status, de.create_by, de.create_time, de.update_by,
de.update_time, de.last_time, de.remark, de.status, de.lock_status, de.location,
de.remaining_power, de.voltage, de.qrcode, de.longitude, de.latitude, de.is_area_out_outage from et_device de
de.remaining_power, de.voltage, de.qrcode, de.longitude, de.latitude, de.is_area_out_outage, de.is_admin_unlocking from et_device de
inner join et_area_dept ad on ad.area_id = de.area_id
inner join sys_dept d on d.dept_id = ad.dept_id
where 1 = 1
@ -209,6 +210,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="longitude != null">longitude = #{longitude},</if>
<if test="latitude != null">latitude = #{latitude},</if>
<if test="isAreaOutOutage != null">is_area_out_outage = #{isAreaOutOutage},</if>
<if test="isAdminUnlocking != null">is_admin_unlocking = #{isAdminUnlocking},</if>
</trim>
where device_id = #{deviceId}
</update>
@ -239,6 +241,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="longitude != null">longitude = #{longitude},</if>
<if test="latitude != null">latitude = #{latitude},</if>
<if test="isAreaOutOutage != null">is_area_out_outage = #{isAreaOutOutage},</if>
<if test="isAdminUnlocking != null">is_admin_unlocking = #{isAdminUnlocking},</if>
</trim>
where sn = #{sn}
</update>

View File

@ -6,6 +6,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<resultMap type="EtFeeRule" id="EtFeeRuleResult">
<result property="ruleId" column="rule_id" />
<result property="areaId" column="area_id" />
<result property="name" column="name" />
<result property="explain" column="explain" />
<result property="status" column="status" />
@ -25,18 +26,24 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectEtFeeRuleVo">
select rule_id, `name`, `explain`,
select rule_id, area_id, `name`, `explain`,
status, auto_refund_deposit, order_exceed_minutes, order_exceed_warn,
free_ride_time, rental_unit, riding_rule, riding_rule_json, charging_cycle, charging_cycle_value,
capped_amount, instructions, create_by, create_time from et_fee_rule
</sql>
<select id="selectEtFeeRuleList" parameterType="EtFeeRule" resultMap="EtFeeRuleResult">
<include refid="selectEtFeeRuleVo"/>
<where>
<if test="name != null and name != ''"> and `name` like concat('%', #{name}, '%')</if>
<if test="status != null and status != ''"> and status = #{status}</if>
</where>
select r.rule_id, r.area_id, d.dept_name area, r.`name`, r.`explain`,
r.status, r.auto_refund_deposit, r.order_exceed_minutes, r.order_exceed_warn,
r.free_ride_time, r.rental_unit, r.riding_rule, r.riding_rule_json, r.charging_cycle, r.charging_cycle_value,
r.capped_amount, r.instructions, r.create_by, r.create_time from et_fee_rule r
left join et_area_dept ad on ad.area_id = r.area_id
left join sys_dept d on d.dept_id = ad.dept_id
where 1 = 1
<if test="name != null and name != ''"> and r.`name` like concat('%', #{name}, '%')</if>
<if test="status != null and status != ''"> and r.status = #{status}</if>
<!-- 数据范围过滤 -->
${params.dataScope}
</select>
<select id="selectEtFeeRuleByRuleId" parameterType="Long" resultMap="EtFeeRuleResult">
@ -53,7 +60,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectRuleInfoListByAreaId" parameterType="Long" resultMap="EtFeeRuleResult">
select r.rule_id, r.`name`, r.`explain`,
select r.rule_id, r.`area_id`, r.`name`, r.`explain`,
r.status, r.auto_refund_deposit, r.order_exceed_minutes, r.order_exceed_warn,
r.free_ride_time, r.rental_unit, r.riding_rule, r.riding_rule_json, r.charging_cycle, r.charging_cycle_value,
r.capped_amount, r.instructions, r.create_by, r.create_time
@ -75,6 +82,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
insert into et_fee_rule
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="name != null">`name`,</if>
<if test="areaId != null">area_id,</if>
<if test="explain != null">`explain`,</if>
<if test="status != null">status,</if>
<if test="autoRefundDeposit != null">auto_refund_deposit,</if>
@ -93,6 +101,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="name != null">#{name},</if>
<if test="areaId != null">#{areaId},</if>
<if test="explain != null">#{explain},</if>
<if test="status != null">#{status},</if>
<if test="autoRefundDeposit != null">#{autoRefundDeposit},</if>
@ -115,6 +124,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
update et_fee_rule
<trim prefix="SET" suffixOverrides=",">
<if test="name != null">`name` = #{name},</if>
<if test="areaId != null">area_id = #{areaId},</if>
<if test="explain != null">`explain` = #{explain},</if>
<if test="status != null">status = #{status},</if>
<if test="autoRefundDeposit != null">auto_refund_deposit = #{autoRefundDeposit},</if>

View File

@ -25,12 +25,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</sql>
<select id="selectEtModelList" parameterType="EtModel" resultMap="EtModelResult">
<include refid="selectEtModelVo"/>
<where>
<if test="model != null and model != ''"> and model = #{model}</if>
<if test="brand != null and brand != ''"> and brand = #{brand}</if>
<if test="operator != null and operator != ''"> and operator = #{operator}</if>
</where>
select m.model_id, m.model, m.brand, m.operator, m.full_voltage, m.low_voltage,
m.full_endurance, m.low_battery_reminder, m.create_by, m.create_time,
m.update_by, m.update_time, m.remark from et_model m
left join sys_dept d on d.dept_id = m.operator
where 1 = 1
<if test="model != null and model != ''"> and m.model = #{model}</if>
<if test="brand != null and brand != ''"> and m.brand = #{brand}</if>
<if test="operator != null and operator != ''"> and m.operator = #{operator}</if>
<!-- 数据范围过滤 -->
${params.dataScope}
</select>
<select id="selectEtModelByModelId" parameterType="Long" resultMap="EtModelResult">

View File

@ -40,6 +40,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="vehicleManagementFee" column="vehicle_management_fee" />
<result property="timeoutMinutes" column="timeout_minutes" />
<result property="autoReplacementOrder" column="auto_replacement_order" />
<result property="parkingReturn" column="parking_return" />
<result property="areaOutReturn" column="area_out_return" />
</resultMap>
<sql id="selectEtOperatingAreaVo">
@ -49,7 +51,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
county, area_out_outage, parking_out_dispatch, area_out_dispatch,
no_riding_outage, authentication, msg_switch, undercharge, error, cast(agreement as char) as agreement, deposit,
outage, appointment_service_fee, dispatch_fee, vehicle_management_fee, timeout_minutes,
auto_replacement_order, area_time_start, area_time_end from et_operating_area
auto_replacement_order, area_time_start, area_time_end, area_out_return, parking_return from et_operating_area
</sql>
<select id="selectEtOperatingAreaList" parameterType="EtOperatingArea" resultMap="EtOperatingAreaResult">
@ -59,7 +61,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
a.county, a.area_out_outage, a.parking_out_dispatch, a.area_out_dispatch,
a.no_riding_outage, a.authentication, a.msg_switch, a.undercharge, a.error, a.agreement, a.deposit,
a.outage, a.appointment_service_fee, a.dispatch_fee, a.vehicle_management_fee, a.timeout_minutes,
a.auto_replacement_order, a.area_time_start, a.area_time_end from et_operating_area a
a.auto_replacement_order, a.area_time_start, a.area_time_end, a.area_out_return, a.parking_return from et_operating_area a
left join et_area_dept ad on ad.area_id = a.area_id
left join sys_dept d on d.dept_id = ad.dept_id
where 1 = 1

View File

@ -16,6 +16,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="status" column="status" />
<result property="delFlag" column="del_flag" />
<result property="parentName" column="parent_name" />
<result property="platformServiceFee" column="platform_service_fee" />
<result property="isProfitSharing" column="is_profit_sharing" />
<result property="appid" column="appid" />
<result property="appSecret" column="app_secret" />
<result property="merchantId" column="merchant_id" />
<result property="apiV3Key" column="api_v3_key" />
<result property="notifyUrl" column="notify_url" />
<result property="privateKeyPath" column="private_key_path" />
<result property="merchantSerialNumber" column="merchant_serial_number" />
<result property="refundNotifyUrl" column="refund_notify_url" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
@ -23,7 +33,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectDeptVo">
select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time
select d.dept_id, d.parent_id, d.ancestors, d.dept_name,
d.order_num, d.leader, d.phone, d.email, d.status,
d.del_flag,d.platform_service_fee, d.is_profit_sharing, d.appid, d.app_secret,
d.merchant_id, d.api_v3_key, d.notify_url, d.private_key_path,d.merchant_serial_number,d.refund_notify_url,
d.create_by, d.create_time
from sys_dept d
</sql>
@ -59,7 +73,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectDeptById" parameterType="Long" resultMap="SysDeptResult">
select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status,
select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status,d.platform_service_fee, d.is_profit_sharing, d.appid, d.app_secret,
d.merchant_id, d.api_v3_key, d.notify_url, d.private_key_path,d.merchant_serial_number,d.refund_notify_url,
(select dept_name from sys_dept where dept_id = d.parent_id) parent_name
from sys_dept d
where d.dept_id = #{deptId}
@ -87,7 +102,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where dept_name=#{deptName} and parent_id = #{parentId} and del_flag = '0' limit 1
</select>
<insert id="insertDept" parameterType="SysDept" useGeneratedKeys="true" keyProperty="deptId">
<select id="selectEtOperatingAreaBySerialNumber" resultMap="SysDeptResult">
<include refid="selectDeptVo"/>
where merchant_serial_number = #{merchantSerialNumber}
</select>
<insert id="insertDept" parameterType="SysDept" useGeneratedKeys="true" keyProperty="deptId">
insert into sys_dept(
<if test="deptId != null and deptId != 0">dept_id,</if>
<if test="parentId != null and parentId != 0">parent_id,</if>
@ -99,6 +119,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="email != null and email != ''">email,</if>
<if test="status != null">status,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="platformServiceFee != null and platformServiceFee != ''">platform_service_fee,</if>
<if test="isProfitSharing != null and isProfitSharing != ''">is_profit_sharing,</if>
<if test="appid != null and appid != ''">appid,</if>
<if test="appSecret != null and appSecret != ''">app_secret,</if>
<if test="merchantId != null and merchantId != ''">merchant_id,</if>
<if test="apiV3Key != null and apiV3Key != ''">api_v3_key,</if>
<if test="notifyUrl != null and notifyUrl != ''">notify_url,</if>
<if test="privateKeyPath != null and privateKeyPath != ''">private_key_path,</if>
<if test="merchantSerialNumber != null and merchantSerialNumber != ''">merchant_serial_number,</if>
<if test="refundNotifyUrl != null and refundNotifyUrl != ''">refund_notify_url,</if>
create_time
)values(
<if test="deptId != null and deptId != 0">#{deptId},</if>
@ -111,6 +141,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="email != null and email != ''">#{email},</if>
<if test="status != null">#{status},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="platformServiceFee != null and platformServiceFee != ''">#{platformServiceFee},</if>
<if test="isProfitSharing != null and isProfitSharing != ''">#{isProfitSharing},</if>
<if test="appid != null and appid != ''">#{appid},</if>
<if test="appSecret != null and appSecret != ''">#{appSecret},</if>
<if test="merchantId != null and merchantId != ''">#{merchantId},</if>
<if test="apiV3Key != null and apiV3Key != ''">#{apiV3Key},</if>
<if test="notifyUrl != null and notifyUrl != ''">#{notifyUrl},</if>
<if test="privateKeyPath != null and privateKeyPath != ''">#{privateKeyPath},</if>
<if test="merchantSerialNumber != null and merchantSerialNumber != ''">#{merchantSerialNumber},</if>
<if test="refundNotifyUrl != null and refundNotifyUrl != ''">#{refundNotifyUrl},</if>
sysdate()
)
</insert>
@ -127,6 +167,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="email != null">email = #{email},</if>
<if test="status != null and status != ''">status = #{status},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
<if test="platformServiceFee != null and platformServiceFee != ''">platform_service_fee = #{platformServiceFee},</if>
<if test="isProfitSharing != null and isProfitSharing != ''">is_profit_sharing = #{isProfitSharing},</if>
<if test="appid != null and appid != ''">appid = #{appid},</if>
<if test="appSecret != null and appSecret != ''">app_secret = #{appSecret},</if>
<if test="merchantId != null and merchantId != ''">merchant_id = #{merchantId},</if>
<if test="apiV3Key != null and apiV3Key != ''">api_v3_key = #{apiV3Key},</if>
<if test="notifyUrl != null and notifyUrl != ''">notify_url = #{notifyUrl},</if>
<if test="privateKeyPath != null and privateKeyPath != ''">private_key_path = #{privateKeyPath},</if>
<if test="merchantSerialNumber != null and merchantSerialNumber != ''">merchant_serial_number = #{merchantSerialNumber},</if>
<if test="refundNotifyUrl != null and refundNotifyUrl != ''">refund_notify_url = #{refundNotifyUrl},</if>
update_time = sysdate()
</set>
where dept_id = #{deptId}