支付相关

This commit is contained in:
13405411873 2024-09-26 18:58:50 +08:00
parent 8310618c2d
commit 977fac06ef
11 changed files with 279 additions and 56 deletions

View File

@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.app.customer;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.custom.service.CustomerMainService;
import cn.iocoder.yudao.module.custom.vo.CustomerMainSaveReqVO;
import cn.iocoder.yudao.module.system.api.user.dto.UserDTO;
@ -50,6 +52,9 @@ public class CustomerAPI {
@PostMapping("/register")
@Operation(summary = "客户自行注册")
public CommonResult<?> createCustomerMain(@Valid @RequestBody CustomerMainSaveReqVO saveReqVO, HttpServletRequest request) {
// 获取当前登录用户
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
saveReqVO.setUserId(loginUser.getId());
//客户类型统一为私人客户
saveReqVO.setTypeCode("01");
//客户来源统一为04-维修
@ -59,7 +64,7 @@ public class CustomerAPI {
try {
UserDTO userDTO = customerMainService.saveCustomer(saveReqVO,SIGN_CREATE);
//注册并登录
return success(loginService.wxLoginByUserId(userDTO.getId(),userDTO.getUsername()));
return success(userDTO);
}catch (ServiceException e){
return error(e);
}

View File

@ -33,6 +33,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@ -221,10 +222,14 @@ public class CustomerMainServiceImpl extends ServiceImpl<CustomerMainMapper, Cus
**/
@Override
public CustomerMainRespVO getUserCustomer() {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
LambdaQueryWrapper<CustomerMain> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(CustomerMain::getUserId,loginUser.getId()).eq(BaseDO::getDeleted,'0');
CustomerMain customerMain = getOne(lambdaQueryWrapper);
if (ObjectUtils.isEmpty(customerMain)){
return null;
}
return getCustomerById(customerMain.getId());
}
@ -280,4 +285,4 @@ public class CustomerMainServiceImpl extends ServiceImpl<CustomerMainMapper, Cus
public CustomerMain getCustomerByCarId(String carId){
return baseMapper.getCustomerByCarId(carId);
}
}
}

View File

@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.company.service.CompanyService;
import cn.iocoder.yudao.module.custom.service.CustomerBalanceService;
@ -15,10 +16,15 @@ import cn.iocoder.yudao.module.order.vo.*;
import cn.iocoder.yudao.module.order.vo.RepairOrderInfoPageReqVO;
import cn.iocoder.yudao.module.order.vo.RepairOrderInfoRespVO;
import cn.iocoder.yudao.module.order.vo.RepairOrderInfoSaveReqVO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.module.tickets.entity.Tickets;
import cn.iocoder.yudao.module.tickets.service.TicketsService;
import cn.iocoder.yudao.util.WechatPayConfig;
import cn.iocoder.yudao.util.WechatPayRequest;
import cn.iocoder.yudao.util.WechatPayUrlEnum;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
@ -26,12 +32,17 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@ -61,6 +72,8 @@ public class RepairOrderInfoServiceImpl extends ServiceImpl<RepairOrderInfoMappe
private WechatPayRequest wechatPayRequest;
@Resource
private TicketsService ticketsService;
@Autowired
private AdminUserService userService;
/**
@ -217,23 +230,41 @@ public class RepairOrderInfoServiceImpl extends ServiceImpl<RepairOrderInfoMappe
*/
@Override
public Map<String,Object> payTransactions(String orderId){
RepairOrderInfo orderInfo = this.getById(orderId);
AdminUserDO user = userService.getUser(orderInfo.getUserId());
// 统一参数封装
Map<String, Object> params = new HashMap<>(8);
params.put("appid", wechatPayConfig.getAppId());
params.put("appid", wechatPayConfig.getRepairAppId());
params.put("mchid", wechatPayConfig.getMchId());
params.put("description", orderInfo.getPayRemark());
params.put("description", "汽修业务");
params.put("out_trade_no", orderInfo.getOrderNo());
params.put("notify_url", wechatPayConfig.getRepairNotifyUrl());
Map<String, Object> amountMap = new HashMap<>(4);
// 金额单位为分
amountMap.put("total", orderInfo.getPayMoney().multiply(BigDecimal.valueOf(100L)).intValue());
amountMap.put("total", orderInfo.getPayMoney().multiply(BigDecimal.valueOf(100L)).longValue());
//人民币
amountMap.put("currency", "CNY");
params.put("amount", amountMap);
// 场景信息
Map<String, Object> sceneInfoMap = new HashMap<>(4);
// 客户端IP
sceneInfoMap.put("payer_client_ip", "127.0.0.1");
// 商户端设备号门店号或收银设备ID
sceneInfoMap.put("device_id", "127.0.0.1");
// 除H5与JSAPI有特殊参数外其他的支付方式都一样
Map<String, Object> payerMap = new HashMap<>(4);
payerMap.put("openid", user.getOpenId());
params.put("payer", payerMap);
params.put("scene_info", sceneInfoMap);
String paramsStr = JSON.toJSONString(params);
String resStr = wechatPayRequest.wechatHttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native",paramsStr);
return JSONObject.parseObject(resStr, new TypeReference<Map<String, Object>>(){});
String resStr = wechatPayRequest.wechatHttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi",paramsStr);
Map<String, Object> resMap = JSONObject.parseObject(resStr);
//Map<String, Object> signMap = paySignMsg(resMap.get("prepay_id").toString(), wechatPayConfig.getAppId(),null);
return resMap;
}
/**
@ -262,4 +293,24 @@ public class RepairOrderInfoServiceImpl extends ServiceImpl<RepairOrderInfoMappe
public RepairOrderCensusVO census(){
return baseMapper.census();
}
// private Map<String, Object> paySignMsg(String prepayId,String appId,String privateKeyStr) throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
// long timeMillis = System.currentTimeMillis();
// String timeStamp = timeMillis/1000+"";
// String nonceStr = timeMillis+"";
// String packageStr = "prepay_id="+prepayId;
// // 公共参数
// Map<String, Object> resMap = new HashMap<>();
// resMap.put("nonceStr",nonceStr);
// resMap.put("timeStamp",timeStamp);
// resMap.put("appId",appId);
// resMap.put("package", packageStr);
// // 使用字段appIdtimeStampnonceStrpackage进行签名
// //从下往上依次生成
// String message = buildMessage(appId, timeStamp, nonceStr, packageStr);
// //签名
// String paySign = sign(message.getBytes("utf-8"), privateKeyStr);
// resMap.put("paySign", paySign);
// resMap.put("signType", "RSA");
// return resMap;
// }
}

View File

@ -86,9 +86,10 @@ public class WechatPayConfig {
private String jcNotifyUrl="https://www.nuoyunr.com/admin-api/payApi/payNotify";
private String jcRefundNotifyUrl="https://www.nuoyunr.com/admin-api/payApi/refundNotify";
private String repairAppId="wxee677d54037bc5ac";
private String repairAppSecret="774bcddc165287da47b0b72b31f1c0a0";
/**
* 获取商户的私钥文件
* @param keyPemPath

View File

@ -0,0 +1,176 @@
package cn.iocoder.yudao.module.app.controller;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.common.CommonErrorCodeConstants;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.app.vo.WxLoginBody;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.permission.dto.RoleReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthLoginReqVO;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthLoginRespVO;
import cn.iocoder.yudao.module.system.controller.admin.user.LoginBody;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
import cn.iocoder.yudao.module.system.service.permission.MenuService;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.util.WechatPayConfig;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.*;
/**
* 登录验证
*
* @author ruoyi
*/
@RestController
@Slf4j
@RequestMapping("/userClient/repair")
public class LoginController {
@Resource
private AdminAuthService loginService;
@Resource
private WechatPayConfig wxConfig;
@Resource
private RestTemplate restTemplate;
@Resource
private SecurityProperties securityProperties;
@PostMapping("/wxLogin")
@TenantIgnore
public CommonResult wxLogin(@RequestBody WxLoginBody wxLoginBody) {
String code = wxLoginBody.getCode();
//秘钥
String encryptedIv = wxLoginBody.getEncryptedIv();
//加密数据
String encryptedData = wxLoginBody.getEncryptedData();
//想微信服务器发送请求获取用户信息
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + wxConfig.getRepairAppId() + "&secret=" + wxConfig.getRepairAppSecret() + "&js_code=" + code + "&grant_type=authorization_code";
String res = restTemplate.getForObject(url, String.class);
JSONObject jsonObject = JSONObject.parseObject(res);
//获取session_key和openid
String sessionKey = jsonObject.getString("session_key");
String openId = jsonObject.getString("openid");
//解密
String decryptResult = "";
try {
//如果没有绑定微信开放平台解析结果是没有unionid的
decryptResult = decrypt(sessionKey, encryptedIv, encryptedData);
} catch (Exception e) {
e.printStackTrace();
return error(500, "微信登录失败!");
}
if (StringUtils.hasText(decryptResult)) {
//如果解析成功,获取token
AuthLoginRespVO loginVO = loginService.wxLoginJc(decryptResult,openId,wxLoginBody.getInviteId());
Map<String, Object> map = new HashMap<>();
map.put("token", loginVO.getAccessToken());
return success(map);
} else {
return error(500, "微信登录失败!");
}
}
@PostMapping("/logout")
@Operation(summary = "登出系统")
public CommonResult<Boolean> logout(HttpServletRequest request) {
String token = SecurityFrameworkUtils.obtainAuthorization(request,
securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
if (StrUtil.isNotBlank(token)) {
loginService.logout(token,1);
}
return success(true);
}
/**
* AES解密
*/
private String decrypt(String sessionKey,String encryptedIv,String encryptedData) throws Exception{
// 转化为字节数组
byte[] key = Base64.decode(sessionKey);
byte[] iv = Base64.decode(encryptedIv);
byte[] encData = Base64.decode(encryptedData);
// 如果密钥不足16位那么就补足
int base =16;
if (key.length % base !=0) {
int groups = key.length / base +(key.length % base != 0 ? 1 : 0);
byte[] temp = new byte[groups * base];
Arrays.fill(temp,(byte) 0);
System.arraycopy(key,0,temp,0,key.length);
key = temp;
}
// 如果初始向量不足16位也补足
if (iv.length % base !=0) {
int groups = iv.length / base +(iv.length % base != 0 ? 1 : 0);
byte[] temp = new byte[groups * base];
Arrays.fill(temp,(byte) 0);
System.arraycopy(iv,0,temp,0,iv.length);
iv = temp;
}
AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
String resultStr = null;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(key,"AES");
cipher.init(Cipher.DECRYPT_MODE,keySpec,ivSpec);
resultStr = new String(cipher.doFinal(encData),"UTF-8");
} catch (Exception e){
// logger.info("解析错误");
e.printStackTrace();
}
// 解析加密后的字符串
return resultStr;
}
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.app.vo;
import lombok.Data;
@Data
public class WxLoginBody {
/**
* 临时登陆凭证 code 只能使用一次
*/
private String code;
/**
* 偏移量
*/
private String encryptedIv;
/**
* 加密数据
*/
private String encryptedData;
//邀请码
private Long inviteId;
}

View File

@ -137,7 +137,7 @@ public class YudaoWebSecurityConfigurerAdapter {
"/admin-api/system/auth/loginApp",
"/admin-api/rescue/driverLogin").anonymous()
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/admin-api/*/login", "/admin-api/*/wxLogin","/admin-api/*/wxLoginJc","/admin-api/*/wxLoginRescue","/admin-api/*/register","/admin-api/*/registerSmsCode","/admin-api/*/registerPhone","/admin-api/*/loginApp","/admin-api/*/loginSmsCode","/admin-api/*/captchaImage","/admin-api/*/pwdSmsCode","/admin-api/*/updatePwd").permitAll()
.antMatchers("/admin-api/*/login", "/admin-api/*/wxLogin","/admin-api/*/wxLoginJc","/admin-api/*/wxLoginRescue","/admin-api/*/registerSmsCode","/admin-api/*/registerPhone","/admin-api/*/loginApp","/admin-api/*/loginSmsCode","/admin-api/*/captchaImage","/admin-api/*/pwdSmsCode","/admin-api/*/updatePwd").permitAll()
// 公共接口 for 小程序
.antMatchers("/admin-api/system/dict/data/list","/admin-api/system/user/profile/avatar","/admin-api/system/user/profile/updateNickName","/admin-api/system/user/profile/saveUserProfile","/admin-api/system/userCar/getUserCar","/admin-api/system/userFeedback/addFeedbackWx").permitAll()
@ -146,7 +146,7 @@ public class YudaoWebSecurityConfigurerAdapter {
// 微信支付接口
.antMatchers("/admin-api/notify/**").permitAll()
.antMatchers("/userClient/pay/**").permitAll()
.antMatchers("/userClient/weChat/**").permitAll()
.antMatchers("/userClient/weChat/**","/userClient/repair/wxLogin").permitAll()
.antMatchers("/admin-api/websocket/**").permitAll()
// 小程序首页
.antMatchers("/admin-api/system/notice/listWx","/admin-api/system/swiper/listWx","/admin-api/system/shopconfig/listWx").permitAll()

View File

@ -60,6 +60,7 @@ public class AdminUserRespDTO {
* 枚举类 {@link SexEnum}
*/
private Integer sex;
private String repairOpenId;
}

View File

@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.system.framework.operatelog.core.DeptParseFunction;
import cn.iocoder.yudao.module.system.framework.operatelog.core.PostParseFunction;
import cn.iocoder.yudao.module.system.framework.operatelog.core.SexParseFunction;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.mzt.logapi.starter.annotation.DiffLogField;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -227,56 +227,12 @@ public class AdminAuthServiceImpl implements AdminAuthService {
public AuthLoginRespVO wxLogin(String decryptResult, String openId, Long inviteId) {
//字符串转json
JSONObject jsonObject = JSONObject.parseObject(decryptResult);
System.out.println(jsonObject);
System.out.println("openId"+openId);
String phoneNumber = jsonObject.getString("phoneNumber");
//还可以获取其他信息
//根据openid判断数据库中是否有该用户
//根据openid查询用户信息
AdminUserDO wxUser = userService.selectUserByPhone(phoneNumber);
//如果查不到则新增查到了则更新
// SysUser user = new SysUser();
// if (wxUser == null) {
// // 新增
// user.setUserName(phoneNumber);
// user.setNickName(phoneNumber);
// user.setPhonenumber(phoneNumber);
// user.setOpenId(openId);
// user.setCreateTime(DateUtils.getNowDate());
// user.setPassword(SecurityUtils.encryptPassword("654321"));
// if (null!=inviteId){
//
// //绑定上级
// user.setInviteId(inviteId);
// //给上级进行积分奖励
// userBalanceService.inviteRewards(inviteId);
// }
// //新增 用户
// userService.insertUser(user);
// }else {
// //更新
// user = wxUser;
// user.setNickName(phoneNumber);
// user.setPhonenumber(phoneNumber);
// user.setUpdateTime(DateUtils.getNowDate());
// user.setOpenId(openId);
// if (ObjectUtil.isEmpty(user.getInviteId())){
// if (null!=inviteId){
// //绑定上级
// user.setInviteId(inviteId);
// //给上级进行积分奖励
// userBalanceService.inviteRewards(inviteId);
// }
// }
// userMapper.updateUser(user);
// }
//组装token信息
// LoginUser loginUser = new LoginUser();
// loginUser.setOpenId(openId);
// //如果有的话设置
// loginUser.setUser(user);
// loginUser.setUserId(user.getUserId());
// 生成token
return createTokenAfterLoginSuccess(wxUser.getId(), wxUser.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
}
@ -419,7 +375,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
List<RoleDO> jcyh = roleService.getRoleListByCodes(Collections.singletonList("jcyh"));
Set<Long> ids = new HashSet<>();
ids.add(jcyh.get(0).getId());
permissionService.assignUserRole(user.getId(),ids);
// permissionService.assignUserRole(user.getId(),ids);
}else {
//更新
user.setId(wxUser.getId());

View File

@ -3,7 +3,7 @@ spring:
name: yudao-server
profiles:
active: local
active: prod
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
@ -230,6 +230,7 @@ yudao:
- /admin-api/rescue/loginJcApp
- /admin-api/system/tenant/getListByWebsite
- /admin-api/rescue/loginQx
- /userClient/repair/wxLogin
websocket:
enable: true # websocket的开关
path: /infra/ws # 路径
@ -285,6 +286,7 @@ yudao:
- /userClient/pay/**
- /userClient/weChat/**
- /userClient/**
ignore-tables:
- system_tenant
- system_tenant_package