This commit is contained in:
nyoung 2024-09-04 22:34:29 +08:00
parent b2db2d3b71
commit 3adaa2e822
10 changed files with 298 additions and 32 deletions

View File

@ -80,6 +80,9 @@ public class WechatPayConfig {
private String jcAppId = "wx5eeea06aeaae4f89";
private String jcAppSecret = "42207958589342d9d1d287b9cb53e289";
private String jcNotifyUrl="https://www.nuoyunr.com/admin-api/payApi/payNotify";
private String jcRefundNotifyUrl="https://www.nuoyunr.com/admin-api/payApi/refundNotify";

View File

@ -1,11 +1,23 @@
package cn.iocoder.yudao.module.payment.controller;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.inspection.service.AppInspectionPartnerService;
import cn.iocoder.yudao.module.partner.entity.PartnerBankInfo;
import cn.iocoder.yudao.module.payment.entity.FzRecord;
import cn.iocoder.yudao.module.payment.entity.OrderInfo;
import cn.iocoder.yudao.module.payment.entity.OrderInfoDetail;
import cn.iocoder.yudao.module.payment.service.IFzRecordService;
import cn.iocoder.yudao.module.payment.service.IOrderInfoDetailService;
import cn.iocoder.yudao.module.payment.service.OrderInfoService;
import cn.iocoder.yudao.module.shop.entity.ShopConfig;
import cn.iocoder.yudao.module.shop.entity.ShopCoupon;
import cn.iocoder.yudao.module.shop.service.IShopConfigService;
import cn.iocoder.yudao.module.shop.service.IShopCouponService;
import cn.iocoder.yudao.module.shop.service.IUserBalanceService;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.util.WechatPayConfig;
@ -15,22 +27,27 @@ import cn.iocoder.yudao.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.partner.service.IPartnerBankInfoService;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.profitsharing.ProfitsharingService;
import com.wechat.pay.java.service.profitsharing.model.CreateOrderReceiver;
import com.wechat.pay.java.service.profitsharing.model.CreateOrderRequest;
import com.wechat.pay.java.service.profitsharing.model.OrdersEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
@RestController
@ -39,7 +56,8 @@ public class WxPayController {
@Resource
private WechatPayConfig wechatPayConfig;
@Autowired
private IShopCouponService shopCouponService;
@Resource
private WechatPayRequest wechatPayRequest;
@Autowired
@ -48,6 +66,17 @@ public class WxPayController {
private IPartnerBankInfoService partnerBankInfoService;
@Autowired
private AdminUserService adminUserService;
@Autowired
private IShopConfigService configService;
@Autowired
private IOrderInfoDetailService orderInfoDetailService;
@Autowired
private IUserBalanceService userBalanceService;
@Autowired
private AppInspectionPartnerService partnerService;
@Autowired
private IFzRecordService fzRecordService;
private final ReentrantLock lock = new ReentrantLock();
/**
* typeh5jsapiappnativesub_jsapi
@ -66,7 +95,7 @@ public class WxPayController {
params.put("mchid", wechatPayConfig.getMchId());
params.put("description", orderInfo.getGoodsTitle());
params.put("out_trade_no", orderInfo.getOrderNo());
params.put("notify_url", wechatPayConfig.getNotifyUrl());
params.put("notify_url", wechatPayConfig.getJcNotifyUrl());
Map<String, Object> amountMap = new HashMap<>(4);
// 金额单位为分
amountMap.put("total", orderInfo.getPayMoney());
@ -117,7 +146,7 @@ public class WxPayController {
params.put("mchid", wechatPayConfig.getMchId());
params.put("description", orderInfo.getGoodsTitle());
params.put("out_trade_no", orderInfo.getOrderNo());
params.put("notify_url", wechatPayConfig.getNotifyUrl());
params.put("notify_url", wechatPayConfig.getJcNotifyUrl());
Map<String, Object> amountMap = new HashMap<>(4);
// 金额单位为分
amountMap.put("total", orderInfo.getPayMoney());
@ -170,7 +199,7 @@ public class WxPayController {
String prepayId = this.toGetPayInfo(wechatPayConfig.getJcAppId(), bankInfo.getMchId(), bankInfo.getApiclientKey(), orderInfo.getPayMoney().intValue()
, user.getJcOpenId(), bankInfo.getSerialNo(), bankInfo.getApiV3Key(), orderInfo.getGoodsTitle(),
wechatPayConfig.getNotifyUrl(), orderInfo.getOrderNo());
Map<String, Object> resMap = paySignMsg(prepayId, wechatPayConfig.getAppId(),bankInfo.getApiclientKey());
Map<String, Object> resMap = paySignMsg(prepayId, wechatPayConfig.getJcAppId(),bankInfo.getApiclientKey());
return resMap;
}
private Map<String, Object> paySignMsg(String prepayId,String appId,String privateKeyStr) throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
@ -261,4 +290,229 @@ public class WxPayController {
return response.getPrepayId();
}
@PostMapping("/payNotify")
public Map<String, String> payNotify(@RequestBody JSONObject jsonObject) {
String method = Thread.currentThread().getStackTrace()[1].getMethodName();
try {
String key = wechatPayConfig.getApiV3Key();
String json = jsonObject.toString();
String associated_data = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.associated_data");
String ciphertext = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.ciphertext");
String nonce = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.nonce");
String decryptData = new AesUtil(key.getBytes(StandardCharsets.UTF_8)).decryptToString(associated_data.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
//验签成功
JSONObject decryptDataObj = JSONObject.parseObject(decryptData, JSONObject.class);
if(lock.tryLock()) {
try {
ShopConfig shopConfig = configService.selectShopConfigById(1L);
// 解密resource中的通知数据
String orderNo = decryptDataObj.get("out_trade_no").toString();
OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo);
//追加订单明细记录
orderInfoDetailService.save(new OrderInfoDetail(orderInfo.getId(),"支付成功",new Date(),orderInfo.getPayMoney(),"0"));
JSONObject balanceObject =new JSONObject();
balanceObject.put("goodsType",orderInfo.getGoodsType());
balanceObject.put("goodsTitle",orderInfo.getGoodsTitle());
if (orderInfo.getOrderStatus().equals("0")){
orderInfo.setTransactionId(decryptDataObj.get("transaction_id").toString());
// 生成16位核销码 加到支付回调里
UUID uuid = UUID.randomUUID();
long mostSignificantBits = uuid.getMostSignificantBits();
long leastSignificantBits = uuid.getLeastSignificantBits();
String combinedBits = mostSignificantBits+ String.valueOf(leastSignificantBits);
String shortUuid = combinedBits.substring(combinedBits.length() - 16);
orderInfo.setAccessCode(shortUuid);
if (orderInfo.getGoodsType().equals("cz")){
balanceObject.put("silverNum", shopConfig.getShopUserSilver().longValue());
balanceObject.put("goldNum", shopConfig.getShopUserGold().longValue());
balanceObject.put("platinum", shopConfig.getShopUserPlatinum().longValue());
//积分充值的逻辑处理
orderInfo.setPayTime(new Date());
//状态直接值为 3 已完成 忽略 使用 评价的过程
orderInfo.setOrderStatus("3");
orderInfoService.updateById(orderInfo);
//处理 用户积分的变化
userBalanceService.addBalance(orderInfo.getPayMoney(),orderInfo.getUserId(),balanceObject);
}else if(orderInfo.getGoodsType().equals("jymd")){
//救援买单 忽略核销过程 直接修改为待评价
orderInfo.setPayTime(new Date());
orderInfo.setOrderStatus("2");
orderInfoService.updateById(orderInfo);
if (!ObjectUtil.isEmpty(orderInfo.getBalance())&&orderInfo.getBalance()>0){
//处理积分
userBalanceService.subtractFrozenBalance(orderInfo.getBalance(),orderInfo.getUserId(),balanceObject);
}
}else {
orderInfo.setPayTime(new Date());
orderInfo.setOrderStatus("1");
orderInfoService.updateById(orderInfo);
if (!ObjectUtil.isEmpty(orderInfo.getIsCoupon())&&orderInfo.getIsCoupon().equals("1")){
ShopCoupon shopCoupon = shopCouponService.selectShopCouponByCouponId(orderInfo.getCouponId());
//处理优惠卷
shopCoupon.setCouponStatus("1");
shopCoupon.setOrderId(orderInfo.getId());
shopCoupon.setUseTime(new Date());
shopCouponService.updateShopCoupon(shopCoupon);
orderInfo.setCouponId(shopCoupon.getCouponId());
orderInfo.setCouponDiscount(orderInfo.getCouponDiscount());
}
if (!ObjectUtil.isEmpty(orderInfo.getBalance())&&orderInfo.getBalance()>0){
//处理积分
userBalanceService.subtractFrozenBalance(orderInfo.getBalance(),orderInfo.getUserId(),balanceObject);
}
//店铺销量+1
if (orderInfo.getPartnerId()!=null){
partnerService.addSalesNum(orderInfo.getPartnerId());
}
}
//最后处理邀请人的积分奖励
AdminUserDO sysUser = adminUserService.getUser(orderInfo.getUserId());
if (ObjectUtil.isNotEmpty(sysUser.getInviteId())){
AdminUserDO inviteUser = adminUserService.getUser(sysUser.getInviteId());
userBalanceService.inviteSpend(inviteUser.getId(),orderInfo.getPayMoney());
}
//处理分账功能
if (ObjectUtil.isNotEmpty(shopConfig.getFzRatio())&&shopConfig.getFzRatio()>0d&&orderInfo.getSkuName().contains("环检")){
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
LambdaQueryWrapper<PartnerBankInfo> queryWrapper =new LambdaQueryWrapper<>();
queryWrapper.eq(PartnerBankInfo::getPartnerId,orderInfo.getPartnerId());
PartnerBankInfo bankInfo = partnerBankInfoService.getOne(queryWrapper);
profitsharing(wechatPayConfig.getAppId(),bankInfo.getMchId(),bankInfo.getApiclientKey(),3000L,
bankInfo.getSerialNo(),bankInfo.getApiV3Key(),orderInfo.getOrderNo(),orderInfo.getTransactionId(),orderInfo.getPartnerId()
,orderInfo.getPartnerName(),orderInfo.getId(),orderInfo.getPayMoney());
}
};
long delay = 300 * 1000; // 一分钟后执行单位是毫秒
timer.schedule(task, delay);
}
}
} finally {
//要主动释放锁
lock.unlock();
}
}
}catch (Exception e){
e.printStackTrace();
}
Map<String, String> res = new HashMap<>();
res.put("code", "SUCCESS");
res.put("message", "成功");
return res;
}
@PostMapping("/profitsharing")
void profitsharing(String appId, String merchantId,String privateKey,Long amount,
String merchantSerialNumber,String apiV3Key,String orderNo,String transactionId
,Long partnerId,String partnerName,Long orderId,Long totalAmount){
try {
Config config =
new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
.privateKey(privateKey)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
// 构建service
ProfitsharingService service = new ProfitsharingService.Builder().config(config).build();
CreateOrderRequest request =new CreateOrderRequest();
request.setAppid(appId);
request.setTransactionId(transactionId);
request.setOutOrderNo(orderNo);
request.setUnfreezeUnsplit(true);
List<CreateOrderReceiver> receivers =new ArrayList<>();
CreateOrderReceiver receiver =new CreateOrderReceiver();
receiver.setType("MERCHANT_ID");
receiver.setAccount(wechatPayConfig.getMchId());
receiver.setName("官方");
receiver.setAmount(amount);
receiver.setDescription("平台收取一定费用");
receivers.add(receiver);
request.setReceivers(receivers);
OrdersEntity order = service.createOrder(request);
FzRecord fzRecord =new FzRecord();
fzRecord.setPartnerId(partnerId);
fzRecord.setPartnerName(partnerName);
fzRecord.setOrderId(orderId);
fzRecord.setOrderNo(orderNo);
fzRecord.setIsSuccess("1");
fzRecord.setReason(JSONObject.toJSONString(order));
fzRecord.setAmount(amount);
fzRecord.setTotalAmount(totalAmount);
fzRecordService.save(fzRecord);
}catch (Exception e){
FzRecord fzRecord =new FzRecord();
fzRecord.setPartnerId(partnerId);
fzRecord.setPartnerName(partnerName);
fzRecord.setOrderId(orderId);
fzRecord.setOrderNo(orderNo);
fzRecord.setIsSuccess("0");
fzRecord.setReason(e.getMessage());
fzRecord.setAmount(amount);
fzRecord.setTotalAmount(totalAmount);
fzRecordService.save(fzRecord);
}
}
@PostMapping("/refundNotify")
public Map<String, String> refundNotify(@RequestBody JSONObject jsonObject) throws GeneralSecurityException, IOException {
String key = wechatPayConfig.getApiV3Key();
String json = jsonObject.toString();
String associated_data = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.associated_data");
String ciphertext = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.ciphertext");
String nonce = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.nonce");
String decryptData = new AesUtil(key.getBytes(StandardCharsets.UTF_8)).decryptToString(associated_data.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
//验签成功
JSONObject decryptDataObj = JSONObject.parseObject(decryptData, JSONObject.class);
if(lock.tryLock()) {
try {
String orderNo = decryptDataObj.get("out_trade_no").toString();
//根据订单编号进行退款处理
OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo);
//追加订单明细记录
orderInfoDetailService.save(new OrderInfoDetail(orderInfo.getId(),"退款成功",new Date(),orderInfo.getPayMoney(),"1"));
if (orderInfo.getOrderStatus().equals("4")){
if (orderInfo.getIsCoupon().equals("1")){
//处理优惠卷
ShopCoupon shopCoupon = shopCouponService.selectShopCouponByCouponId(orderInfo.getCouponId());
shopCoupon.setCouponStatus("0");
shopCouponService.hfStatus(shopCoupon);
}
//申请退款的状态
//处理订单状态
orderInfo.setOrderStatus("5");
orderInfoService.updateById(orderInfo);
if (null!=orderInfo.getBalance()&&orderInfo.getBalance()>0){
//1处理积分
Long balance = orderInfo.getBalance();
JSONObject balanceObject =new JSONObject();
balanceObject.put("goodsType",orderInfo.getGoodsType());
balanceObject.put("goodsTitle",orderInfo.getGoodsTitle());
userBalanceService.refundBalance(orderInfo.getUserId(),balance,balanceObject);
}
}
//log.warn("=========== 根据订单号,做幂等处理 ===========");
} finally {
//要主动释放锁
lock.unlock();
}
}
//成功应答
Map<String, String> res = new HashMap<>();
res.put("code", "SUCCESS");
res.put("message", "成功");
return res;
}
}

View File

@ -52,5 +52,6 @@ public interface OrderInfoService extends IService<OrderInfo> {
List<OrderInfo> orderListPc(OrderInfo orderInfo);
OrderInfo getOrderByOrderNo(String orderNo);
}

View File

@ -799,5 +799,12 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
return baseMapper.orderListPc(orderInfo);
}
@Override
public OrderInfo getOrderByOrderNo(String orderNo) {
LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(OrderInfo::getOrderNo, orderNo);
return this.getOne(queryWrapper);
}
}

View File

@ -412,7 +412,7 @@ FROM
COUNT(1)
FROM
inspection_appointment ia
where ia.partner_id = #{partnerId} and appointment_day = #{formDate}
where ia.deleted = 0 and ia.partner_id = #{partnerId} and appointment_day = #{formDate}
order by create_time desc
</select>
<select id="getPickNum" resultType="java.lang.Long">
@ -421,7 +421,7 @@ FROM
FROM
inspection_pick_car ipc
inner join inspection_appointment ia on ia.pick_car_id = ipc.id
where ipc.partner_id = #{partnerId} and ia.appointment_day = #{formDate}
where ipc.deleted = 0 and ia.deleted= 0 and ipc.partner_id = #{partnerId} and ia.appointment_day = #{formDate}
order by ipc.create_time desc
</select>
</mapper>

View File

@ -98,9 +98,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
FROM
inspection_appointment ip
INNER JOIN system_users su ON ip.user_id = su.id
left JOIN order_info oi ON ip.order_id = oi.id
left join shop_user_car suc on suc.car_id = oi.user_car_id
where ip.partner_id = #{partnerId}
left JOIN order_info oi ON ip.order_id = oi.id and oi.deleted=0
left join shop_user_car suc on suc.car_id = oi.user_car_id and suc.deleted=0
where ip.deleted=0 and ip.partner_id = #{partnerId}
<if test="phoneNum!=null and phoneNum!=''">
and su.mobile like concat('%',#{phoneNum},'%')
</if>
@ -115,7 +115,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
INNER JOIN system_users su ON ip.user_id = su.id
left JOIN order_info oi ON ip.order_id = oi.id
left join shop_user_car suc on suc.car_id = oi.user_car_id
where ip.user_id = #{userId}
where ip.deleted=0 and ip.user_id = #{userId}
order by ip.create_time desc
</select>
</mapper>

View File

@ -95,6 +95,7 @@ public class UserSaveReqVO {
private Integer userAge;
private String rescueOpenId;
private String jcOpenId;
private Long inviteId;

View File

@ -111,4 +111,6 @@ public class AdminUserDO extends TenantBaseDO {
private String openId;
private Long inviteId;
}

View File

@ -23,7 +23,7 @@ public interface AdminUserMapper extends BaseMapperX<AdminUserDO> {
}
default AdminUserDO selectByMobile(String mobile) {
return null;
return getUserByMobileWithoutTenant(mobile);
}
default PageResult<AdminUserDO> selectPage(UserPageReqVO reqVO, Collection<Long> deptIds) {

View File

@ -401,7 +401,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
user.setNickname(phoneNumber);
user.setMobile(phoneNumber);
user.setPassword(passwordEncoder.encode("123456"));
user.setRescueOpenId(openId);
user.setJcOpenId(openId);
user.setTenantId(1L);
if (null!=inviteId){
//绑定上级
@ -422,20 +422,18 @@ public class AdminAuthServiceImpl implements AdminAuthService {
permissionService.assignUserRole(user.getId(),ids);
}else {
//更新
// user.setId(wxUser.getId());
// user.setNickname(phoneNumber);
// user.setMobile(phoneNumber);
// user.setRescueOpenId(openId);
// user.setId(1L);
// if (ObjectUtil.isEmpty(user.getInviteId())){
// if (null!=inviteId){
// //绑定上级
// user.setInviteId(inviteId);
// //给上级进行积分奖励
//// userBalanceService.inviteRewards(inviteId);
// }
// }
// userService.updateUser(user);
user.setId(wxUser.getId());
user.setNickname(phoneNumber);
user.setJcOpenId(openId);
if (ObjectUtil.isEmpty(user.getInviteId())){
if (null!=inviteId){
//绑定上级
user.setInviteId(inviteId);
//给上级进行积分奖励
// userBalanceService.inviteRewards(inviteId);
}
}
userService.updateUser(user);
}
// 生成token