diff --git a/electripper-admin/src/main/java/com/ruoyi/web/controller/app/AppController.java b/electripper-admin/src/main/java/com/ruoyi/web/controller/app/AppController.java index ab8d939..4936c7c 100644 --- a/electripper-admin/src/main/java/com/ruoyi/web/controller/app/AppController.java +++ b/electripper-admin/src/main/java/com/ruoyi/web/controller/app/AppController.java @@ -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); } diff --git a/electripper-admin/src/main/java/com/ruoyi/web/controller/app/AppVerifyController.java b/electripper-admin/src/main/java/com/ruoyi/web/controller/app/AppVerifyController.java index 2a709af..159e4db 100644 --- a/electripper-admin/src/main/java/com/ruoyi/web/controller/app/AppVerifyController.java +++ b/electripper-admin/src/main/java/com/ruoyi/web/controller/app/AppVerifyController.java @@ -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()); //实名判断 diff --git a/electripper-admin/src/main/java/com/ruoyi/web/controller/iot/receive/ReceiveController.java b/electripper-admin/src/main/java/com/ruoyi/web/controller/iot/receive/ReceiveController.java index 6ab63b0..0dbac07 100644 --- a/electripper-admin/src/main/java/com/ruoyi/web/controller/iot/receive/ReceiveController.java +++ b/electripper-admin/src/main/java/com/ruoyi/web/controller/iot/receive/ReceiveController.java @@ -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, "超出营运区断电"); } diff --git a/electripper-admin/src/main/resources/application.yml b/electripper-admin/src/main/resources/application.yml index bab787d..4b27b92 100644 --- a/electripper-admin/src/main/resources/application.yml +++ b/electripper-admin/src/main/resources/application.yml @@ -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 diff --git a/electripper-common/src/main/java/com/ruoyi/common/config/WxPayConfig.java b/electripper-common/src/main/java/com/ruoyi/common/config/WxPayConfig.java index fc5f09f..080a381 100644 --- a/electripper-common/src/main/java/com/ruoyi/common/config/WxPayConfig.java +++ b/electripper-common/src/main/java/com/ruoyi/common/config/WxPayConfig.java @@ -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(); +//// } +// +//} diff --git a/electripper-common/src/main/java/com/ruoyi/common/constant/ServiceConstants.java b/electripper-common/src/main/java/com/ruoyi/common/constant/ServiceConstants.java index 01a6b02..833497f 100644 --- a/electripper-common/src/main/java/com/ruoyi/common/constant/ServiceConstants.java +++ b/electripper-common/src/main/java/com/ruoyi/common/constant/ServiceConstants.java @@ -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----------------------------*/ + } diff --git a/electripper-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java b/electripper-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java index 8e4de58..01a13ec 100644 --- a/electripper-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java +++ b/electripper-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java @@ -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; } diff --git a/electripper-common/src/main/java/com/ruoyi/common/utils/DateUtils.java b/electripper-common/src/main/java/com/ruoyi/common/utils/DateUtils.java index 1deb6b7..860ff0a 100644 --- a/electripper-common/src/main/java/com/ruoyi/common/utils/DateUtils.java +++ b/electripper-common/src/main/java/com/ruoyi/common/utils/DateUtils.java @@ -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); + } } diff --git a/electripper-common/src/main/java/com/ruoyi/common/utils/wx/AccessTokenUtil.java b/electripper-common/src/main/java/com/ruoyi/common/utils/wx/AccessTokenUtil.java index 7ef9c1a..90c3904 100644 --- a/electripper-common/src/main/java/com/ruoyi/common/utils/wx/AccessTokenUtil.java +++ b/electripper-common/src/main/java/com/ruoyi/common/utils/wx/AccessTokenUtil.java @@ -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; diff --git a/electripper-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java b/electripper-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java index 6045bd7..26558d3 100644 --- a/electripper-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java +++ b/electripper-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java @@ -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); diff --git a/electripper-system/src/main/java/com/ruoyi/system/domain/AsDevice.java b/electripper-system/src/main/java/com/ruoyi/system/domain/AsDevice.java index 13db153..496a735 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/domain/AsDevice.java +++ b/electripper-system/src/main/java/com/ruoyi/system/domain/AsDevice.java @@ -140,6 +140,9 @@ public class AsDevice extends BaseEntityPlus implements Serializable { /** 是否发送过断电指令 */ private String isAreaOutOutage; + /** 是否是管理员开锁:0-否;1-是(用于控制运营区外是否断电判断) */ + private String isAdminUnlocking; + /** 正在进行中的订单 */ @TableField(exist = false) private List etOrders; diff --git a/electripper-system/src/main/java/com/ruoyi/system/domain/EtDividendDetail.java b/electripper-system/src/main/java/com/ruoyi/system/domain/EtDividendDetail.java index 9177218..ee838e8 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/domain/EtDividendDetail.java +++ b/electripper-system/src/main/java/com/ruoyi/system/domain/EtDividendDetail.java @@ -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; diff --git a/electripper-system/src/main/java/com/ruoyi/system/domain/EtOperatingArea.java b/electripper-system/src/main/java/com/ruoyi/system/domain/EtOperatingArea.java index a82014b..624c655 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/domain/EtOperatingArea.java +++ b/electripper-system/src/main/java/com/ruoyi/system/domain/EtOperatingArea.java @@ -162,4 +162,10 @@ public class EtOperatingArea extends BaseEntityPlus implements Serializable /** 电量低于多少值自动生成换电订单*/ private Integer autoReplacementOrder; + + /** 停车点还车:0-关闭;1-开启*/ + private String parkingReturn; + + /** 运营区外还车:0-关闭;1-开启*/ + private String areaOutReturn; } diff --git a/electripper-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java b/electripper-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java index 384a9b6..61dbc1d 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java +++ b/electripper-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java @@ -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); } diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java b/electripper-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java index f228208..2c8b84d 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java @@ -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); } diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/IWxPayService.java b/electripper-system/src/main/java/com/ruoyi/system/service/IWxPayService.java index e126d8b..5ad8fe8 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/IWxPayService.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/IWxPayService.java @@ -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 receivers); + public OrdersEntity createOrder(SysDept sysDept, String transactionId, List 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); } diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/impl/AsDeviceServiceImpl.java b/electripper-system/src/main/java/com/ruoyi/system/service/impl/AsDeviceServiceImpl.java index 7dad74e..fd48bb5 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/impl/AsDeviceServiceImpl.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/impl/AsDeviceServiceImpl.java @@ -436,58 +436,55 @@ public class AsDeviceServiceImpl extends ServiceImpl 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 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 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 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); diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/impl/CallbackServiceImpl.java b/electripper-system/src/main/java/com/ruoyi/system/service/impl/CallbackServiceImpl.java index 11f4418..f93551a 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/impl/CallbackServiceImpl.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/impl/CallbackServiceImpl.java @@ -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 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 areaId1 = etAreaDeptMapper.selectList(new QueryWrapper().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 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); + } + } } diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtFeeRuleServiceImpl.java b/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtFeeRuleServiceImpl.java index 9ef52c5..c718c46 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtFeeRuleServiceImpl.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtFeeRuleServiceImpl.java @@ -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 selectEtFeeRuleList(EtFeeRule etFeeRule) { return etFeeRuleMapper.selectEtFeeRuleList(etFeeRule); diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtModelServiceImpl.java b/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtModelServiceImpl.java index 7972931..99f236c 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtModelServiceImpl.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtModelServiceImpl.java @@ -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 selectEtModelList(EtModel etModel) { List etModels = etModelMapper.selectEtModelList(etModel); diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtOperatingAreaServiceImpl.java b/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtOperatingAreaServiceImpl.java index ed3a093..aee02a8 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtOperatingAreaServiceImpl.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtOperatingAreaServiceImpl.java @@ -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 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)){ diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java b/electripper-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java index 0da2583..be3ec00 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java @@ -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; + } + /** * 递归列表 */ diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/electripper-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java index 3e446dd..f40ce66 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -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); } diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/impl/WxPayService.java b/electripper-system/src/main/java/com/ruoyi/system/service/impl/WxPayService.java index d7a73bb..b0a212c 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/impl/WxPayService.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/impl/WxPayService.java @@ -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 areaId1 = etAreaDeptMapper.selectList(new QueryWrapper().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 areaId1 = etAreaDeptMapper.selectList(new QueryWrapper().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 areaId1 = etAreaDeptMapper.selectList(new QueryWrapper().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 receivers) { + public OrdersEntity createOrder(SysDept sysDept,String transactionId,List 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 checkAndParse(HttpServletRequest request, String body, Class 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 checkAndParse(HttpServletRequest request, String body, Class 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); diff --git a/electripper-system/src/main/java/com/ruoyi/system/task/EtTask.java b/electripper-system/src/main/java/com/ruoyi/system/task/EtTask.java index 01bef20..385d224 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/task/EtTask.java +++ b/electripper-system/src/main/java/com/ruoyi/system/task/EtTask.java @@ -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); diff --git a/electripper-system/src/main/resources/mapper/system/AsDeviceMapper.xml b/electripper-system/src/main/resources/mapper/system/AsDeviceMapper.xml index 6c2d66c..1954e37 100644 --- a/electripper-system/src/main/resources/mapper/system/AsDeviceMapper.xml +++ b/electripper-system/src/main/resources/mapper/system/AsDeviceMapper.xml @@ -30,17 +30,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + - 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 - - - and `name` like concat('%', #{name}, '%') - and status = #{status} - + 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 + and r.`name` like concat('%', #{name}, '%') + and r.status = #{status} + + ${params.dataScope} - - - and model = #{model} - and brand = #{brand} - and operator = #{operator} - + 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 + and m.model = #{model} + and m.brand = #{brand} + and m.operator = #{operator} + + ${params.dataScope} @@ -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 diff --git a/electripper-system/src/main/resources/mapper/system/SysDeptMapper.xml b/electripper-system/src/main/resources/mapper/system/SysDeptMapper.xml index 2d72851..7437508 100644 --- a/electripper-system/src/main/resources/mapper/system/SysDeptMapper.xml +++ b/electripper-system/src/main/resources/mapper/system/SysDeptMapper.xml @@ -16,6 +16,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + + + + + + + + @@ -23,7 +33,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - 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 @@ -59,7 +73,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + + + insert into sys_dept( dept_id, parent_id, @@ -99,6 +119,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" email, status, create_by, + platform_service_fee, + is_profit_sharing, + appid, + app_secret, + merchant_id, + api_v3_key, + notify_url, + private_key_path, + merchant_serial_number, + refund_notify_url, create_time )values( #{deptId}, @@ -111,6 +141,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{email}, #{status}, #{createBy}, + #{platformServiceFee}, + #{isProfitSharing}, + #{appid}, + #{appSecret}, + #{merchantId}, + #{apiV3Key}, + #{notifyUrl}, + #{privateKeyPath}, + #{merchantSerialNumber}, + #{refundNotifyUrl}, sysdate() ) @@ -127,6 +167,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" email = #{email}, status = #{status}, update_by = #{updateBy}, + platform_service_fee = #{platformServiceFee}, + is_profit_sharing = #{isProfitSharing}, + appid = #{appid}, + app_secret = #{appSecret}, + merchant_id = #{merchantId}, + api_v3_key = #{apiV3Key}, + notify_url = #{notifyUrl}, + private_key_path = #{privateKeyPath}, + merchant_serial_number = #{merchantSerialNumber}, + refund_notify_url = #{refundNotifyUrl}, update_time = sysdate() where dept_id = #{deptId}