This commit is contained in:
韩鹏辉
2024-05-23 15:23:08 +08:00
parent 49fe8fe877
commit d969550aa3
2477 changed files with 340990 additions and 0 deletions

185
jeepay-agent/pom.xml Normal file
View File

@@ -0,0 +1,185 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <!-- POM模型版本 -->
<groupId>com.jeequan</groupId> <!-- 组织名, 类似于包名 -->
<artifactId>jeepay-9219-agent</artifactId> <!-- 项目名称 -->
<packaging>jar</packaging> <!-- 项目的最终打包类型/发布形式, 可选[jar, war, pom, maven-plugin]等 -->
<version>${isys.version}</version> <!-- 项目当前版本号 -->
<description>Jeepay计全支付系统 [代理商后台管理端]</description> <!-- 项目描述 -->
<url>https://www.jeequan.com</url>
<parent>
<groupId>com.jeequan</groupId>
<artifactId>jeepay</artifactId>
<version>Final</version>
</parent>
<!-- 项目属性 -->
<properties>
<projectRootDir>${basedir}/../</projectRootDir>
</properties>
<!-- 项目依赖声明 -->
<dependencies>
<!-- 依赖[ service ]包, 会自动传递依赖[ core ]包。 -->
<dependency>
<groupId>com.jeequan</groupId>
<artifactId>jeepay-components-db</artifactId>
</dependency>
<!-- 依赖[ rpc-thirdparty ]包, 会自动传递依赖[ core , service ]包。 -->
<dependency>
<groupId>com.jeequan</groupId>
<artifactId>jeepay-components-3rd</artifactId>
</dependency>
<!-- 依赖[ oss ]包 -->
<dependency>
<groupId>com.jeequan</groupId>
<artifactId>jeepay-components-oss</artifactId>
</dependency>
<!-- 依赖[ mq ]包 -->
<dependency>
<groupId>com.jeequan</groupId>
<artifactId>jeepay-components-mq</artifactId>
</dependency>
<!-- 依赖[ bizcommons ]包 -->
<dependency>
<groupId>com.jeequan</groupId>
<artifactId>jeepay-components-bizcommons</artifactId>
</dependency>
<!-- 依赖 sping-boot-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion> <!-- 删除spring boot默认json映射器 Jackson 引入fastJSON -->
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</exclusion>
<exclusion> <!-- hibernate.validator插件一般不使用 -->
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- spring-security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- spring-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- 添加redis支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 引入 jeepay-sdk-java -->
<dependency>
<groupId>com.jeequan</groupId>
<artifactId>jeepay-sdk-java</artifactId>
</dependency>
<!-- webSocket -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
<!--阿里云短信依赖-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
</dependency>
<!-- 阿里大于 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
</dependency>
<!-- 生成二维码工具包 zxing -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
</dependency>
</dependencies>
<!-- 作为可执行jar -->
<build>
<finalName>${project.artifactId}</finalName>
<!-- resources资源配置项 -->
<resources>
<!-- 通用资源文件 -->
<resource><directory>src/main/resources</directory><includes><include>**/*.*</include></includes></resource>
<!-- 放置通用配置yml文件 开发时仅配置一套参数即可。 实际生产环境下应在每个项目下 与jar同级目录下新建application.yml覆写对应参数。 -->
<resource>
<directory>../conf/devCommons</directory>
<includes><include>**/*.yml</include></includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
<outputDirectory>${session.executionRootDirectory}/target/</outputDirectory>
</configuration> <!-- 包含本地jar文件 -->
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,151 @@
package com.jeequan.jeepay.agent.aop;
import com.alibaba.fastjson.JSON;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.beans.RequestKitBean;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.security.JeeUserDetails;
import com.jeequan.jeepay.db.entity.SysLog;
import com.jeequan.jeepay.service.impl.SysLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
/**
* 方法级日志切面组件
*
* @author terrfly
* @modify pangxiaoyu
* @date 2021-04-27 15:50
*/
@Component
@Aspect
public class MethodLogAop{
private static final Logger logger = LoggerFactory.getLogger(MethodLogAop.class);
@Autowired private SysLogService sysLogService;
@Autowired private RequestKitBean requestKitBean;
/**
* 异步处理线程池
*/
private final static ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
/**
* 切点
*/
@Pointcut("@annotation(com.jeequan.jeepay.core.aop.MethodLog)")
public void methodCachePointcut() { }
/**
* 切面
* @param point
* @return
* @throws Throwable
*/
@Around("methodCachePointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
final SysLog sysLog = new SysLog();
//处理切面任务 发生异常将向外抛出 不记录日志
Object result = point.proceed();
try {
// 基础日志信息
setBaseLogInfo(point, sysLog, JeeUserDetails.getCurrentUserDetails());
sysLog.setOptResInfo(JSON.toJSON(result).toString());
scheduledThreadPool.execute(() -> sysLogService.save(sysLog));
} catch (Exception e) {
logger.error("methodLogError", e);
}
return result;
}
/**
* @author: pangxiaoyu
* @date: 2021/6/7 14:04
* @describe: 记录异常操作请求信息
*/
@AfterThrowing(pointcut = "methodCachePointcut()", throwing="e")
public void doException(JoinPoint joinPoint, Throwable e) throws Exception{
final SysLog sysLog = new SysLog();
// 基础日志信息
setBaseLogInfo(joinPoint, sysLog, JeeUserDetails.getCurrentUserDetails());
sysLog.setOptResInfo(e instanceof BizException ? e.getMessage() : "请求异常");
scheduledThreadPool.execute(() -> sysLogService.save(sysLog));
}
/**
* 获取方法中的中文备注
* @param joinPoint
* @return
* @throws Exception
*/
public static String getAnnotationRemark(JoinPoint joinPoint) throws Exception {
Signature sig = joinPoint.getSignature();
Method m = joinPoint.getTarget().getClass().getMethod(joinPoint.getSignature().getName(), ((MethodSignature) sig).getParameterTypes());
MethodLog methodCache = m.getAnnotation(MethodLog.class);
if (methodCache != null) {
return methodCache.remark();
}
return "";
}
/**
* @author: pangxiaoyu
* @date: 2021/6/7 14:12
* @describe: 日志基本信息 公共方法
*/
private void setBaseLogInfo(JoinPoint joinPoint, SysLog sysLog, JeeUserDetails userDetails) throws Exception {
// 使用point.getArgs()可获取request仅限于spring MVC参数包含request改为通过contextHolder获取。
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//请求参数
sysLog.setOptReqParam( requestKitBean.getReqParamJSON().toJSONString() );
//注解备注
sysLog.setMethodRemark(getAnnotationRemark(joinPoint));
//包名 方法名
String methodName = joinPoint.getSignature().getName();
String packageName = joinPoint.getThis().getClass().getName();
if (packageName.indexOf("$$EnhancerByCGLIB$$") > -1 || packageName.indexOf("$$EnhancerBySpringCGLIB$$") > -1) { // 如果是CGLIB动态生成的类
packageName = packageName.substring(0, packageName.indexOf("$$"));
}
sysLog.setMethodName(packageName + "." + methodName);
sysLog.setReqUrl(request.getRequestURL().toString());
sysLog.setUserIp(requestKitBean.getClientIp());
sysLog.setCreatedAt(new Date());
sysLog.setSysType(CS.SYS_ROLE_TYPE.AGENT);
if (userDetails != null) {
sysLog.setUserId(JeeUserDetails.getCurrentUserDetails().getSysUser().getSysUserId());
sysLog.setUserName(JeeUserDetails.getCurrentUserDetails().getSysUser().getRealname());
sysLog.setSysType(JeeUserDetails.getCurrentUserDetails().getSysUser().getSysType());
}
}
}

View File

@@ -0,0 +1,66 @@
package com.jeequan.jeepay.agent.bootstrap;
import cn.hutool.core.date.DatePattern;
import cn.hutool.crypto.SmUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;
import com.jeequan.jeepay.agent.config.SystemYmlConfig;
import com.jeequan.jeepay.service.impl.SysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 项目初始化操作
* 比如初始化配置文件, 读取基础数据, 资源初始化等。 避免在Main函数中写业务代码。
* CommandLineRunner / ApplicationRunner都可以达到要求 只是调用参数有所不同。
*
* @author terrfly
*
* @date 2021-04-27 15:50
*/
@Component
public class InitRunner implements CommandLineRunner {
@Autowired private SystemYmlConfig systemYmlConfig;
@Autowired private SysConfigService sysConfigService;
@Override
public void run(String... args) throws Exception {
// 配置是否使用缓存模式
SysConfigService.IS_USE_CACHE = systemYmlConfig.getCacheConfig();
// 初始化系统秘钥
SysConfigService.DB_ENCRYPT_SECRET = systemYmlConfig.getDbEncryptSecret();
SysConfigService.DB_ENCRYPT_SM4 = SmUtil.sm4(SysConfigService.DB_ENCRYPT_SECRET.getBytes());
SysConfigService.HTTP_MESSAGE_ENCRYPT_SECRET = systemYmlConfig.getHttpMessageEncryptSecret();
SysConfigService.HTTP_MESSAGE_ENCRYPT_SM4 = SmUtil.sm4(SysConfigService.HTTP_MESSAGE_ENCRYPT_SECRET.getBytes());
// 支持服务商
SysConfigService.IS_HAS_AGENT_ENT = true;
// 检查是否支持会员
SysConfigService.IS_HAS_MEMBER_ENT = sysConfigService.getById(SysConfigService.MEMBER_ENT_CONFIG) != null;
// 配置是否通信加密 和 密码修改
SysConfigService.HTTP_MSG_IS_ENCRYPT = sysConfigService.getDBSecurityConfig().httpMsgIsEncrypt();
SysConfigService.PWD_EXPIRED_MUST_RESET = sysConfigService.getDBSecurityConfig().passwordExpiredIsMustModify();
// 配置 平台通信秘钥
SysConfigService.PLATFORM_API_SECRET = sysConfigService.getDBSecurityConfig().getPlatformApiSecret();
//初始化处理fastjson格式
SerializeConfig serializeConfig = SerializeConfig.getGlobalInstance();
serializeConfig.put(Date.class, new SimpleDateFormatSerializer(DatePattern.NORM_DATETIME_PATTERN));
//解决json 序列化时候的 $ref问题
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
}
}

View File

@@ -0,0 +1,87 @@
package com.jeequan.jeepay.agent.bootstrap;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.EnableScheduling;
import java.util.Arrays;
/**
* spring-boot 主启动程序
*
* @author terrfly
*
* @date 2022-03-14 08:50
*/
@SpringBootApplication
@EnableScheduling
@MapperScan("com.jeequan.jeepay.service.mapper") //Mybatis mapper接口路径
@ComponentScan(basePackages = "com.jeequan.jeepay.*") //由于MainApplication没有在项目根目录 需要配置basePackages属性使得成功扫描所有Spring组件
@Configuration
public class JeepayAgentApplication {
/** main启动函数 **/
public static void main(String[] args) {
//启动项目
SpringApplication.run(JeepayAgentApplication.class, args);
}
/** 支持搜索 {} [] 否则 springboot 提示 HTTP Status 400 Bad Request **/
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory (){
// 修改内置的 tomcat 容器配置
TomcatServletWebServerFactory tomcatServlet = new TomcatServletWebServerFactory();
tomcatServlet.addConnectorCustomizers( connector -> connector.setProperty("relaxedQueryChars", "[]{}") );
return tomcatServlet ;
}
/** fastJson 配置信息 **/
@Bean
public HttpMessageConverters fastJsonConfig(){
// 开启 FastJSON 安全模式!
ParserConfig.getGlobalInstance().setSafeMode(true);
//新建fast-json转换器
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
//fast-json 配置信息
FastJsonConfig config = new FastJsonConfig();
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
converter.setFastJsonConfig(config);
//设置响应的 Content-Type
converter.setSupportedMediaTypes(Arrays.asList(new MediaType[]{MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8}));
return new HttpMessageConverters(converter);
}
/** Mybatis plus 分页插件 **/
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
}

View File

@@ -0,0 +1,70 @@
package com.jeequan.jeepay.agent.config;
import com.jeequan.jeepay.core.cache.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
/**
* redis管理类
*
* @author terrfly
*
* @date 2021-04-27 15:50
*/
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private Integer port;
@Value("${spring.redis.timeout}")
private Integer timeout;
@Value("${spring.redis.database}")
private Integer defaultDatabase;
@Value("${spring.redis.password}")
private String password;
/** 作用:不同系统的前缀。 a.当连接不同的database时可以为空(物理隔离) b.当redis集群时因为必须同一个database所以需通过前缀区分不同系统的业务。 **/
@Value("${spring.redis.sys-prefix-key}")
private String sysPrefixKey;
/** 当前系统的redis缓存操作对象 (主对象) **/
@Primary
@Bean(name = "defaultStringRedisTemplate")
public StringRedisTemplate sysStringRedisTemplate() {
// 赋值前缀key
RedisUtil.SYS_PREFIX_KEY = sysPrefixKey;
StringRedisTemplate template = new StringRedisTemplate();
LettuceConnectionFactory jedisConnectionFactory = new LettuceConnectionFactory();
jedisConnectionFactory.setHostName(host);
jedisConnectionFactory.setPort(port);
jedisConnectionFactory.setTimeout(timeout);
if (!StringUtils.isEmpty(password)) {
jedisConnectionFactory.setPassword(password);
}
if (defaultDatabase != 0) {
jedisConnectionFactory.setDatabase(defaultDatabase);
}
jedisConnectionFactory.afterPropertiesSet();
template.setConnectionFactory(jedisConnectionFactory);
return template;
}
}

View File

@@ -0,0 +1,40 @@
package com.jeequan.jeepay.agent.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 系统Yml配置参数定义Bean
*
* @author terrfly
*
* @date 2021-04-27 15:50
*/
@Component
@ConfigurationProperties(prefix="isys")
@Data
public class SystemYmlConfig {
/** 是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时应开启此配置或在nginx统一配置允许跨域] **/
private Boolean allowCors;
/** 生成jwt的秘钥。 要求每个系统有单独的秘钥管理机制。 **/
private String jwtSecret;
/** DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] **/
private String dbEncryptSecret;
/** web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] **/
private String httpMessageEncryptSecret;
/** 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更! **/
private String sysRSA2PrivateKey;
/**支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更! **/
private String sysRSA2PublicKey;
/** 是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常 false表示直接查询DB. **/
private Boolean cacheConfig;
}

View File

@@ -0,0 +1,225 @@
package com.jeequan.jeepay.agent.ctrl;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.config.SystemYmlConfig;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.ctrls.AbstractCtrl;
import com.jeequan.jeepay.core.entity.SysUser;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.BaseModel;
import com.jeequan.jeepay.core.model.security.JeeUserDetails;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.MchInfo;
import com.jeequan.jeepay.db.entity.MchStore;
import com.jeequan.jeepay.db.entity.PayInterfaceDefine;
import com.jeequan.jeepay.service.impl.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* 通用ctrl类
*
* @author terrfly
* @modify zhuxiao
* @date 2021-04-27 15:50
*/
public abstract class CommonCtrl extends AbstractCtrl {
@Autowired protected SystemYmlConfig mainConfig;
@Autowired protected SysConfigService sysConfigService;
@Autowired protected MchInfoService mchInfoService;
@Autowired protected MchStoreService mchStoreService;
@Autowired protected PayInterfaceDefineService payInterfaceDefineService;
@Autowired protected AgentInfoService agentInfoService;
/** 获取当前用户ID */
protected JeeUserDetails getCurrentUser(){
return (JeeUserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
/** 获取当前商户ID **/
protected String getCurrentAgentNo() {
return getCurrentUser().getSysUser().getBelongInfoId();
}
/**
* 获取当前用户登录IP
* @return
*/
protected String getIp() {
return getClientIp();
}
/**
* 校验当前用户是否为超管
* @return
*/
protected ApiRes checkIsAdmin() {
SysUser sysUser = getCurrentUser().getSysUser();
if (sysUser.getUserType() != SysUser.UEST_TYPE_ADMIN) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}else {
return null;
}
}
/** model 存入服务商名称 **/
public void setAgentName(List<? extends BaseModel> modeList) {
if(modeList == null || modeList.isEmpty()){
return ;
}
ArrayList<String> agentNoList = new ArrayList<>();
for (BaseModel model:modeList) {
JSONObject json = (JSONObject) JSONObject.toJSON(model);
String agentNo = json.getString("agentNo");
agentNoList.add(agentNo);
}
List<AgentInfo> agentInfoList = agentInfoService.list(AgentInfo.gw().select(AgentInfo::getAgentNo, AgentInfo::getAgentName).in(AgentInfo::getAgentNo, agentNoList));
for (BaseModel model:modeList) {
JSONObject json = (JSONObject) JSONObject.toJSON(model);
String agentNo = json.getString("agentNo");
if(StringUtils.isBlank(agentNo)) {
continue;
}
for (AgentInfo info:agentInfoList) {
if (agentNo.equals(info.getAgentNo())) {
model.addExt("agentName", info.getAgentName());
}
}
}
}
/** model 存入商户名称 **/
public void setMchName(List<? extends BaseModel> modeList) {
if(modeList == null || modeList.isEmpty()){
return ;
}
ArrayList<String> mchNoList = new ArrayList<>();
for (BaseModel model:modeList) {
JSONObject json = (JSONObject) JSONObject.toJSON(model);
String mchNo = json.getString("mchNo");
mchNoList.add(mchNo);
}
List<MchInfo> mchInfoList = mchInfoService.list(MchInfo.gw().select(MchInfo::getMchNo, MchInfo::getMchName).in(MchInfo::getMchNo, mchNoList));
for (BaseModel model:modeList) {
JSONObject json = (JSONObject) JSONObject.toJSON(model);
String mchNo = json.getString("mchNo");
if(StringUtils.isBlank(mchNo)) {
continue;
}
for (MchInfo info:mchInfoList) {
if (mchNo.equals(info.getMchNo())) {
model.addExt("mchName", info.getMchName());
}
}
}
}
/** model 存入门店名称 **/
public void setStoreName(List<? extends BaseModel> modeList) {
if (modeList == null || modeList.isEmpty()) {
return;
}
ArrayList<String> storeIdList = new ArrayList<>();
for (BaseModel model : modeList) {
JSONObject json = (JSONObject) JSONObject.toJSON(model);
String storeId = json.getString("storeId");
storeIdList.add(storeId);
}
List<MchStore> mchInfoList = mchStoreService.list(MchStore.gw().select(MchStore::getStoreId, MchStore::getStoreName).in(MchStore::getStoreId, storeIdList));
for (BaseModel model : modeList) {
JSONObject json = (JSONObject) JSONObject.toJSON(model);
String storeId = json.getString("storeId");
if (storeId == null) {
continue;
}
for (MchStore store : mchInfoList) {
if (storeId.equals(store.getStoreId())) {
model.addExt("storeName", store.getStoreName());
}
}
}
}
/** model 存入支付接口名称 **/
public void setIfName(List<? extends BaseModel> modeList) {
if(modeList == null || modeList.isEmpty()){
return ;
}
ArrayList<String> ifCodeList = new ArrayList<>();
for (BaseModel model:modeList) {
JSONObject json = (JSONObject) JSONObject.toJSON(model);
String ifCode = json.getString("ifCode");
ifCodeList.add(ifCode);
}
List<PayInterfaceDefine> defineList = payInterfaceDefineService.list(PayInterfaceDefine.gw().select(PayInterfaceDefine::getIfCode, PayInterfaceDefine::getIfName).in(PayInterfaceDefine::getIfCode, ifCodeList));
for (BaseModel model : modeList) {
JSONObject json = (JSONObject) JSONObject.toJSON(model);
String ifCode = json.getString("ifCode");
if(StringUtils.isBlank(ifCode)) {
continue;
}
for (PayInterfaceDefine define : defineList) {
if (ifCode.equals(define.getIfCode())) {
model.addExt("ifName", define.getIfName());
}
}
}
}
/** 判断当前用户是否有某个权限 */
public boolean currentUserHasEnt(String ent){
return getCurrentUser().getAuthorities().contains(new SimpleGrantedAuthority("ENT_MCH_APPLYMENT_PAY_CONFIG"));
}
/** 根据服务商号查询服务商下的商户号List **/
public List<String> getMchNoListByAgentNo(String agentNo) {
if (StringUtils.isBlank(agentNo)) {
return null;
}
AgentInfo agentInfo = agentInfoService.getById(agentNo);
if (agentInfo == null || agentInfo.getState() != CS.YES) {
throw new BizException("服务商不存在或状态不正确");
}
List<MchInfo> list = mchInfoService.list(MchInfo.gw().eq(com.jeequan.jeepay.core.entity.MchInfo::getAgentNo, agentNo));
if (CollUtil.isEmpty(list)) {
return null;
}
List<String> mchNoList = new LinkedList<>();
list.forEach(mchInfo -> mchNoList.add(mchInfo.getMchNo()));
return mchNoList;
}
}

View File

@@ -0,0 +1,267 @@
package com.jeequan.jeepay.agent.ctrl;
import cn.hutool.core.codec.Base64;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.service.AuthService;
import com.jeequan.jeepay.bizcommons.manage.auth.AuthByQrcodeManage;
import com.jeequan.jeepay.converter.BaseConverter;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.cache.ITokenService;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.jwt.JWTPayload;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.security.JeeUserDetails;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.core.utils.TreeDataBuilder;
import com.jeequan.jeepay.core.utils.google.GoogleAuth;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.SysEntitlement;
import com.jeequan.jeepay.db.entity.SysUserEntity;
import com.jeequan.jeepay.service.impl.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 当前登录者的信息相关接口
*
* @author terrfly
* @modify zhuxiao
* @date 2021-04-27 15:50
*/
@RestController
@RequestMapping("api/current")
public class CurrentUserController extends CommonCtrl{
@Autowired private SysEntitlementService sysEntitlementService;
@Autowired private SysUserService sysUserService;
@Autowired private SysUserAuthService sysUserAuthService;
@Autowired private AgentInfoService agentInfoService;
@Autowired private BaseConverter baseConverter;
@RequestMapping(value="/user", method = RequestMethod.GET)
public ApiRes currentUserInfo() {
///当前用户信息
JeeUserDetails jeeUserDetails = getCurrentUser();
SysUserEntity user = sysUserService.getById(jeeUserDetails.getSysUser().getSysUserId());
//1. 当前用户所有权限ID集合
List<String> entIdList = new ArrayList<>();
jeeUserDetails.getAuthorities().forEach(r->entIdList.add(r.getAuthority()));
List<SysEntitlement> allMenuList = new ArrayList<>(); //所有菜单集合
//2. 查询出用户所有菜单集合 (包含左侧显示菜单 和 其他类型菜单 )
if(!entIdList.isEmpty()){
allMenuList = sysEntitlementService.list(SysEntitlement.gw()
.in(SysEntitlement::getEntId, entIdList)
.in(SysEntitlement::getEntType, Arrays.asList(CS.ENT_TYPE.MENU_LEFT, CS.ENT_TYPE.MENU_OTHER))
.eq(SysEntitlement::getSysType, CS.SYS_ROLE_TYPE.AGENT)
.eq(SysEntitlement::getState, CS.PUB_USABLE));
}
//4. 转换为json树状结构
JSONArray jsonArray = (JSONArray) JSON.toJSON(allMenuList);
List<JSONObject> allMenuRouteTree = new TreeDataBuilder(jsonArray,
"entId", "pid", "children", "entSort", true)
.buildTreeObject();
//5. 所有权限ID集合
user.addExt("entIdList", entIdList);
user.addExt("allMenuRouteTree", allMenuRouteTree);
user.addExt("mchType", jeeUserDetails.getMchType());
//6. 获取服务商简称
AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());
user.addExt("shortName",agentInfo.getAgentShortName());
// 7. 程序是否支持会员
user.addExt("isHasMemberEnt", SysConfigService.IS_HAS_MEMBER_ENT);
//8.获取邀请码链接信息 商户注册
if (StringUtils.isNotEmpty(user.getInviteCode())) {
// 邀请码二维码地址
String mchRegisterUrl = String.format("%s/register", sysConfigService.getDBApplicationConfig().getMchSiteUrl());
user.addExt("inviteCodeUrl", String.format("%s?c=%s", mchRegisterUrl, user.getInviteCode()));
}
if (StringUtils.isNotEmpty(user.getInviteCode())) {
// 服务商邀请码二维码地址
String agtRegisterUrl = String.format("%s/register", sysConfigService.getDBApplicationConfig().getAgentSiteUrl());
user.addExt("agtInviteCodeUrl", String.format("%s?c=%s", agtRegisterUrl, user.getInviteCode()));
}
return ApiRes.ok(user);
}
/** 修改个人信息 */
@MethodLog(remark = "修改个人信息")
@RequestMapping(value="/user", method = RequestMethod.PUT)
public ApiRes modifyCurrentUserInfo() {
//修改头像
String avatarUrl = getValString("avatarUrl");
String realname = getValString("realname");
Byte sex = getValByte("sex");
//编辑预留信息
String safeWord = getValString("safeWord");
SysUserEntity updateRecord = new SysUserEntity();
updateRecord.setSysUserId(getCurrentUser().getSysUser().getSysUserId());
if (StringUtils.isNotEmpty(avatarUrl)) {
updateRecord.setAvatarUrl(avatarUrl);
}
if (StringUtils.isNotEmpty(realname)) {
updateRecord.setRealname(realname);
}
if (sex != null) {
updateRecord.setSex(sex);
}
if (StringUtils.isNotEmpty(safeWord)) {
updateRecord.setSafeWord(safeWord);
}
sysUserService.updateById(updateRecord);
//保存redis最新数据
JeeUserDetails currentUser = getCurrentUser();
SysUserEntity sysUserEntity = sysUserService.getById(getCurrentUser().getSysUser().getSysUserId());
currentUser.setSysUser(baseConverter.toModel(sysUserEntity));
ITokenService.refData(currentUser);
return ApiRes.ok();
}
/** modifyPwd */
@MethodLog(remark = "修改密码")
@RequestMapping(value="modifyPwd", method = RequestMethod.PUT)
public ApiRes modifyPwd() throws BizException{
Long opSysUserId = getCurrentUser().getSysUser().getSysUserId();
//更改密码,验证当前用户信息
String currentUserPwd = Base64.decodeStr(getValStringRequired("originalPwd")); //当前用户登录密码
//验证当前密码是否正确
if(!sysUserAuthService.validateCurrentUserPwd(currentUserPwd)){
throw new BizException("原密码验证失败!");
}
String opUserPwd = Base64.decodeStr(getValStringRequired("confirmPwd"));
// 验证原密码与新密码是否相同
if (opUserPwd.equals(currentUserPwd)) {
throw new BizException("新密码与原密码不能相同!");
}
sysUserAuthService.resetAuthInfo(opSysUserId, null, null, true, opUserPwd, CS.SYS_ROLE_TYPE.AGENT);
//调用登出接口
return logout();
}
/** 登出 */
@MethodLog(remark = "退出")
@RequestMapping(value="logout", method = RequestMethod.POST)
public ApiRes logout() throws BizException{
ITokenService.removeIToken(getCurrentUser().getCacheKey(), getCurrentUser().getSysUser().getSysUserId());
return ApiRes.ok();
}
/** MFA验证信息 */
@GetMapping("/mfaInfo")
@MethodLog(remark = "MFA验证信息")
public ApiRes mfaInfo() throws BizException{
SysUserEntity currentUser = sysUserService.getById(getCurrentUser().getSysUserId());
JSONObject resJson = new JSONObject();
resJson.put("mfaBindState", currentUser.getMfaBindState());
resJson.put("telPhone", currentUser.getTelphone());
// 是否展示MFA绑定信息 [未绑定时显示]
if (currentUser.getMfaBindState() == CS.NO) {
String secretKey = sysUserService.getById(currentUser.getSysUserId()).getMfaSecretKey();
// 更新用户验证秘钥
if (StringUtils.isEmpty(secretKey)) {
secretKey = GoogleAuth.generateSecretKey();
sysUserService.updateMFASecret(currentUser.getSysUserId(), secretKey, null);
}
String qrcodeUrl = GoogleAuth.getQRBarcode(
sysConfigService.getOemConfig().getSysName() + "_服务商" +"("+ currentUser.getTelphone() + ")"
, secretKey);
resJson.put("mfaBindUrl", qrcodeUrl);
resJson.put("mfaSecretKey", secretKey);
}
return ApiRes.ok(resJson);
}
/** MFA验证 绑定 */
@RequestMapping(value="mfaBind", method = RequestMethod.PUT)
@MethodLog(remark = "MFA验证绑定")
public ApiRes mfaBind() throws BizException{
String verCode = getValStringRequired("verCode");
Long userId = getCurrentUser().getSysUserId();
// 验证验证码
sysUserService.checkMFACode(userId, verCode);
// 绑定MFA验证
sysUserService.bindMFA(userId);
return ApiRes.ok();
}
/** MFA验证 解绑 */
@RequestMapping(value="mfaRelieve", method = RequestMethod.PUT)
@MethodLog(remark = "MFA验证解除")
public ApiRes mfaRelieve() throws BizException{
String verCode = getValStringRequired("verCode");
Long userId = getCurrentUser().getSysUserId();
// 验证验证码
sysUserService.checkMFACode(userId, verCode);
// 解除MFA验证
sysUserService.relieveMFA(userId, CS.SYS_ROLE_TYPE.AGENT);
return ApiRes.ok();
}
/** app扫码登录接口 */
@PostMapping("qrcode/login")
public ApiRes loginQrcodeConfirm(){
String qrcodeNo = getValStringRequired("qrcodeNo");
String qrCodeStatus = getValStringRequired("qrcodeStatus");
if (!StringUtils.equalsAny(qrCodeStatus, AuthByQrcodeManage.QRCODE_STATUS_SCANED, AuthByQrcodeManage.QRCODE_STATUS_CANCELED,
AuthByQrcodeManage.QRCODE_STATUS_CONFIRMED)) {
return ApiRes.customFail("二维码错误");
}
// 更新状态:等待扫码 --> 已扫
if (qrCodeStatus.equals(AuthByQrcodeManage.QRCODE_STATUS_SCANED)) {
AuthByQrcodeManage.updateQrcodeStatusWaiting2Scaned(qrcodeNo);
return ApiRes.ok();
// 更新状态:已扫 --> 取消
}else if (qrCodeStatus.equals(AuthByQrcodeManage.QRCODE_STATUS_CANCELED)) {
AuthByQrcodeManage.updateQrcodeStatusScaned2Canceled(CS.SYS_ROLE_TYPE.AGENT, qrcodeNo);
return ApiRes.ok();
}
// 更新状态:已扫 --> 确认登录
JSONObject tokenJSON = SpringBeansUtil.getBean(AuthService.class).authByAppQrcode(getCurrentUser().getSysUserId(), JWTPayload.LOGIN_PAGE_TYPE.WEB);
// 更新状态:已扫 --> 确认登录
AuthByQrcodeManage.updateQrcodeStatusScaned2Confirmed(qrcodeNo, tokenJSON.toJSONString());
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,239 @@
package com.jeequan.jeepay.agent.ctrl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.utils.DateKit;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.service.impl.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 统计相关接口
*
* @author terrfly
* @date 2022-03-16 15:50
*/
@RestController
@RequestMapping("/api/stat")
public class StatController extends CommonCtrl{
@Autowired private InfoAccountService infoAccountService;
@Autowired private MchInfoService mchInfoService;
@Autowired private AgentInfoService agentInfoService;
@Autowired private PayOrderService payOrderService;
@Autowired private MchStoreDeviceService mchStoreDeviceService;
@Autowired private SysUserService sysUserService;
@Autowired private MchQrcodeCardService mchQrcodeCardService;
/** 统计数据 **/
@PreAuthorize("hasAnyAuthority('ENT_C_MAIN_AGENT_COUNT', 'ENT_AGENT_STATISTIC_COUNT')")
@RequestMapping(value="/index", method = RequestMethod.GET)
public ApiRes currentUserInfo() {
JSONObject paramJSON = getReqParamJSON();
String agentNo = null;
List<String> agentSubList = null;
// 统计数据类型countType 1-服务商本身数据 2-我与全部下级服务商数据 3-服务商号搜索
Byte countType = paramJSON.getByte("countType");
if (countType != null && countType == 2) {
agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
} else if (countType != null && countType == 3) {
agentNo = getValStringRequired("agentNo");
}else {
agentNo = getCurrentAgentNo();
}
// 拓展员参数
if (getCurrentUser().isEpUser()) {
paramJSON.put("epUserId", getCurrentUser().getSysUser().getSysUserId());
}
// 1. 钱包余额
InfoAccount infoAccount = infoAccountService.queryById(agentNo, CS.SYS_ROLE_TYPE.AGENT);
JSONObject result = new JSONObject();
result.put("realBalanceAmount", infoAccount == null ? 0L : infoAccount.getBalanceAmount());
result.put("unAmount", infoAccount == null ? 0L : infoAccount.getUnAmount());
result.put("auditProfitAmount", infoAccount == null ? 0L : infoAccount.getAuditProfitAmount());
// 页面上的钱包余额
Long availableBalanceAmount = infoAccount == null ? 0L : infoAccount.getBalanceAmount() - infoAccount.getUnAmount();
result.put("availableBalanceAmount", availableBalanceAmount);
AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());
// 冻结金额 及 冻结原因
Long freezeAmount = agentInfo == null ? 0L : agentInfo.getFreezeAmount();
result.put("freezeAmount", freezeAmount);
result.put("freezeDesc", agentInfo == null ? "" : agentInfo.getFreezeDesc());
// 可提现金额(页面上的钱包余额-冻结金额)
result.put("allowTakeAmount", Math.max(availableBalanceAmount - freezeAmount, 0L));
JSONObject mchJson = mchInfoService.mchCount(agentNo, agentSubList, paramJSON);
result.put("mchCount", mchJson);
JSONObject agentJson = agentInfoService.agentCount(agentNo, agentSubList, paramJSON);
result.put("agentCount", agentJson);
// 日交易统计
String mchNo = paramJSON.getString("mchNo");
Map<String, Object> countMap = payOrderService.tradeCount(mchNo, agentNo, agentSubList, paramJSON);
// 订单统计
result.put("orderCount", countMap);
// 今日交易笔数
result.put("orderTodayCount", countMap.get("payCount"));
// 今日交易金额
result.put("orderTodaySum", countMap.get("payAmount"));
// 码牌总数
long qrCodeCardAllCount = mchQrcodeCardService.count(
MchQrcodeCard.gw()
.eq(MchQrcodeCard::getAgentNo, getCurrentAgentNo())
.eq(MchQrcodeCard::getQrcState, CS.YES));
result.put("qrCodeCardAllCount", qrCodeCardAllCount);
// 已绑定的码牌
long qrCodeCardBindCount = mchQrcodeCardService.count(
MchQrcodeCard.gw()
.eq(MchQrcodeCard::getAgentNo, getCurrentAgentNo())
.eq(MchQrcodeCard::getQrcState, CS.YES)
.eq(MchQrcodeCard::getBindState, CS.YES));
result.put("qrCodeCardBindCount", qrCodeCardBindCount);
// 剩余空码
result.put("qrCodeCardUnBindCount", qrCodeCardAllCount - qrCodeCardBindCount);
// 云喇叭总数
long speakerAllCount = mchStoreDeviceService.count(MchStoreDevice.gw()
.eq(MchStoreDevice::getAgentNo, getCurrentAgentNo())
.eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_SPEAKER)
);
result.put("speakerAllCount", speakerAllCount);
// 未绑定喇叭数
long speakerUnCount = mchStoreDeviceService.count(MchStoreDevice.gw()
.eq(MchStoreDevice::getAgentNo, getCurrentAgentNo())
.eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_SPEAKER)
.eq(MchStoreDevice::getBindState, CS.NO)
);
result.put("speakerUnCount", speakerUnCount);
// 云打印总数
long printerAllCount = mchStoreDeviceService.count(MchStoreDevice.gw()
.eq(MchStoreDevice::getAgentNo, getCurrentAgentNo())
.eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_PRINTER)
);
result.put("printerAllCount", printerAllCount);
// 未绑定打印数
long printerUnCount = mchStoreDeviceService.count(MchStoreDevice.gw()
.eq(MchStoreDevice::getAgentNo, getCurrentAgentNo())
.eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_PRINTER)
.eq(MchStoreDevice::getBindState, CS.NO)
);
result.put("printerUnCount", printerUnCount);
// 扫码pos机总数
result.put("posAllCount", mchStoreDeviceService.count(MchStoreDevice.gw()
.eq(MchStoreDevice::getAgentNo, getCurrentAgentNo())
.eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_POS)
));
// 未绑定扫码pos数
result.put("posUnCount", mchStoreDeviceService.count(MchStoreDevice.gw()
.eq(MchStoreDevice::getAgentNo, getCurrentAgentNo())
.eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_POS)
.eq(MchStoreDevice::getBindState, CS.NO)
));
// 智能pos机总数
result.put("posAllCount", mchStoreDeviceService.count(MchStoreDevice.gw()
.eq(MchStoreDevice::getAgentNo, getCurrentAgentNo())
.eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_AUTO_POS)
));
// 未绑定智能pos数
result.put("posUnCount", mchStoreDeviceService.count(MchStoreDevice.gw()
.eq(MchStoreDevice::getAgentNo, getCurrentAgentNo())
.eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_AUTO_POS)
.eq(MchStoreDevice::getBindState, CS.NO)
));
return ApiRes.ok(result);
}
/**
* @author: xiaoyu
* @date: 2022/3/23 16:39
* @describe: 拓展员商户统计数据
*/
@RequestMapping(value="/userChart", method = RequestMethod.GET)
public ApiRes userChart() {
Long sysUserId = getValLongRequired("sysUserId");
String dateRange = getValString("queryDateRange");
SysUserEntity sysUserEntity = sysUserService.getById(sysUserId);
if (sysUserEntity == null || !sysUserEntity.getBelongInfoId().equals(getCurrentAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
// 返回数据
JSONObject result = new JSONObject();
result.put("mchAllCount", 0);
result.put("mchTodayAddCount", 0);
result.put("mchOnNetCount", 0);
result.put("mchOnNetNewCount", 0);
result.put("payAllAmount", 0);
result.put("payAmount", 0);
// 拓展员邀请的商户
List<MchInfo> list = mchInfoService.list(MchInfo.gw().eq(MchInfo::getCreatedUid, sysUserId));
if (CollUtil.isEmpty(list)) {
return ApiRes.ok(result);
}
String createdStart = null;
String createdEnd = null;
if (StringUtils.isNotEmpty(dateRange)) {
// 获取查询时间请求参数 [开始时间, 结束时间]
Date[] queryDateRangeArray = DateKit.getQueryDateRange(dateRange);
createdStart = DateUtil.formatDateTime(queryDateRangeArray[0]);
createdEnd = DateUtil.formatDateTime(queryDateRangeArray[1]);
}
// 商户总数
long mchAllCount = mchInfoService.mchCount(null, sysUserId, createdStart, createdEnd);
result.put("mchAllCount", mchAllCount);
// 按时间搜索商户数
long mchTodayAddCount = mchInfoService.mchCount(null, sysUserId, createdStart, createdEnd);
result.put("mchTodayAddCount", mchTodayAddCount);
// 商户入网总数
long mchOnNetCount = mchInfoService.mchApplyCount(null, sysUserId, createdStart, createdEnd);
result.put("mchOnNetCount", mchOnNetCount);
// 按时间搜索商户入网数
long mchOnNetNewCount = mchInfoService.mchApplyCount(null, sysUserId, createdStart, createdEnd);
result.put("mchOnNetNewCount", mchOnNetNewCount);
BigDecimal payAllAmount = payOrderService.totalAmount(null, sysUserId, createdStart, createdEnd);
result.put("payAllAmount", payAllAmount);
BigDecimal payAmount = payOrderService.totalAmount(null, sysUserId, createdStart, createdEnd);
result.put("payAmount", payAmount);
return ApiRes.ok(result);
}
}

View File

@@ -0,0 +1,37 @@
package com.jeequan.jeepay.agent.ctrl.account;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.AccountChangeInfo;
import com.jeequan.jeepay.service.impl.AccountChangeInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* TODO
*
* @author crystal
* @date 2023/12/6 15:11
*/
@RestController
@RequestMapping("/api/accountChange")
public class AccountChangeInfoController extends CommonCtrl {
@Autowired private AccountChangeInfoService accountChangeInfoService;
@PreAuthorize("hasAuthority('ENT_ACCOUNT_CHANGE_LIST')")
@GetMapping
public ApiRes list() {
AccountChangeInfo info = getObject(AccountChangeInfo.class);
JSONObject paramJSON = getReqParamJSON();
LambdaQueryWrapper<AccountChangeInfo> wrapper = AccountChangeInfo.gw(info);
Page<AccountChangeInfo> pages = accountChangeInfoService.pageList(getIPage(),wrapper,info,paramJSON);
return ApiRes.page(pages);
}
}

View File

@@ -0,0 +1,259 @@
package com.jeequan.jeepay.agent.ctrl.account;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.DesensitizedUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.applyment.CashoutFee;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.CashoutRecord;
import com.jeequan.jeepay.db.entity.InfoAccount;
import com.jeequan.jeepay.service.impl.AgentInfoService;
import com.jeequan.jeepay.service.impl.CashoutRecordService;
import com.jeequan.jeepay.service.impl.InfoAccountService;
import com.jeequan.jeepay.service.impl.SysConfigService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 提现结算记录表
*
* @author xiaoyu
* @date 2022/3/21 10:00
*/
@RestController
@RequestMapping("/api/cashout")
public class CashoutRecordController extends CommonCtrl {
@Autowired private CashoutRecordService cashoutRecordService;
@Autowired private AgentInfoService agentInfoService;
@Autowired private SysConfigService sysConfigService;
@Autowired private InfoAccountService infoAccountService;
/**
* @author: xiaoyu
* @date: 2022/3/21 10:01
* @describe: 提现记录
*/
@PreAuthorize("hasAuthority('ENT_CASHOUT_RECORD_LIST')")
@GetMapping
public ApiRes list() {
CashoutRecord record = getObject(CashoutRecord.class);
JSONObject paramJSON = getReqParamJSON();
record.setInfoId(getCurrentAgentNo());
record.setInfoType(CS.SYS_ROLE_TYPE.AGENT);
LambdaQueryWrapper<CashoutRecord> wrapper = CashoutRecord.gw();
IPage<CashoutRecord> pages = cashoutRecordService.listByPage(getIPage(), record, paramJSON, wrapper);
pages.getRecords().stream().forEach(i -> {
i.setSettAccountName(DesensitizedUtil.chineseName(i.getSettAccountName()));
i.setSettAccountTelphone(DesensitizedUtil.mobilePhone(i.getSettAccountTelphone()));
i.setSettAccountNo(DesensitizedUtil.bankCard(i.getSettAccountNo()));
// 平台手续费不对服务商显示
i.setTransferPlatformCostAmount(null); i.setTransferPlatformMchfeeAmount(null);
i.setTransferMchAppId(null);
i.setTransferIfCode(null);
i.setTransferOrderId(null);
});
return ApiRes.page(pages);
}
/**
* @author: xiaoyu
* @date: 2022/3/21 10:21
* @describe: 提现结算记录详情
*/
@PreAuthorize("hasAuthority('ENT_CASHOUT_RECORD_DETAIL')")
@GetMapping("/{rid}")
public ApiRes detail(@PathVariable("rid") String rid) {
Byte originData = getValByteDefault("originData", CS.YES);
CashoutRecord record = cashoutRecordService.getById(rid);
if (CS.NO == originData) {
// 数据脱敏
record.setSettAccountName(DesensitizedUtil.chineseName(record.getSettAccountName()));
record.setSettAccountTelphone(DesensitizedUtil.mobilePhone(record.getSettAccountTelphone()));
record.setSettAccountNo(DesensitizedUtil.bankCard(record.getSettAccountNo()));
}
if (record == null) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
if (!record.getInfoId().equals(getCurrentAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
// 钱包余额
InfoAccount infoAccount = infoAccountService.queryById(getCurrentAgentNo(), CS.SYS_ROLE_TYPE.AGENT);
record.addExt("realBalanceAmount", infoAccount == null ? 0L : infoAccount.getBalanceAmount());
record.addExt("unAmount", infoAccount == null ? 0L : infoAccount.getUnAmount());
record.addExt("auditProfitAmount", infoAccount == null ? 0L : infoAccount.getAuditProfitAmount());
// 页面上的钱包余额
Long availableBalanceAmount = infoAccount == null ? 0L : infoAccount.getBalanceAmount() - infoAccount.getUnAmount();
record.addExt("availableBalanceAmount", availableBalanceAmount);
AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());
// 冻结金额 及 冻结原因
Long freezeAmount = agentInfo == null ? 0L : agentInfo.getFreezeAmount();
record.addExt("freezeAmount", freezeAmount);
record.addExt("freezeDesc", agentInfo == null ? "" : agentInfo.getFreezeDesc());
// 可提现金额(页面上的钱包余额-冻结金额)
record.addExt("allowTakeAmount", Math.max(availableBalanceAmount - freezeAmount, 0L));
// 平台手续费不对服务商显示
record.setTransferPlatformCostAmount(null); record.setTransferPlatformMchfeeAmount(null);
record.setTransferMchAppId(null);
record.setTransferIfCode(null);
record.setTransferOrderId(null);
return ApiRes.ok(record);
}
/**
* @author: xiaoyu
* @date: 2022/3/21 10:21
* @describe: 发起提现
*/
@MethodLog( remark = "佣金提现")
@PreAuthorize("hasAuthority('ENT_CASHOUT_RECORD_SETT')")
@PostMapping("/sett")
public ApiRes sett() {
String sipw = Base64.decodeStr(getValStringRequired("sipw"));
// 查询当前服务商结算信息
AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());
if(StringUtils.isEmpty(agentInfo.getSipw())){
throw new BizException("当前未设置支付密码,请进入[账号中心-系统配置-安全管理]设置支付密码");
}
if(!new BCryptPasswordEncoder().matches(sipw, agentInfo.getSipw())){
throw new BizException("支付密码验证失败!");
}
// 结算参数
AgentInfo infoParams = getObject(AgentInfo.class);
if (infoParams == null) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
if (StringUtils.isEmpty(agentInfo.getSettAccountType()) || StringUtils.isEmpty(agentInfo.getSettAccountNo())) {
throw new BizException("请先联系平台配置结算账户信息");
}
if (StringUtils.isEmpty(infoParams.getContactTel()) || StringUtils.isEmpty(infoParams.getContactName())) {
throw new BizException("结算用户名/联系人手机号不可为空");
}
// 提现金额 元转分
Long applyAmount = Long.valueOf(AmountUtil.convertDollar2Cent(getValStringRequired("amount")));
// 提现金额小于最大可提现金额才允许发起提现
InfoAccount infoAccount = infoAccountService.queryById(agentInfo.getAgentNo(), CS.SYS_ROLE_TYPE.AGENT);
// 页面上的钱包余额
Long availableBalanceAmount = infoAccount == null ? 0L : infoAccount.getBalanceAmount() - infoAccount.getUnAmount();
// 可提现金额(页面上的钱包余额-冻结金额)单位:分
if (applyAmount > Math.max(availableBalanceAmount - agentInfo.getFreezeAmount(), 0L)) {
throw new BizException("提现金额超限,请刷新页面后重试");
}
CashoutRecord record = getObject(CashoutRecord.class);
record.setApplyAmount(applyAmount);
record.setState(CashoutRecord.CASHOUT_STATE_AUDIT_ING); // 待审核
record.setInfoId(getCurrentAgentNo());
record.setInfoType(CS.SYS_ROLE_TYPE.AGENT);
record.setInfoName(agentInfo.getAgentShortName());
record.setSettType(CashoutRecord.SETT_TYPE_COMM);
CashoutFee cashoutFee = null;
// 使用默认
if(agentInfo.getCashoutFeeRuleType() == 1){
cashoutFee = JSON.parseObject(sysConfigService.getById("castOutFeeRule").getConfigVal(), CashoutFee.class);
}else{
cashoutFee = JSON.parseObject(agentInfo.getCashoutFeeRule(), CashoutFee.class);
}
if(cashoutFee.getApplyLimit() != null && record.getApplyAmount() < cashoutFee.getApplyLimit() ){
throw new BizException("提现额度不可小于" + AmountUtil.convertCent2Dollar(cashoutFee.getApplyLimit()) + "");
}
MutablePair<String, Long> feePair = cashoutFee.calFeeAndSnapshot(record.getApplyAmount());
record.setSettFeeRule(feePair.left);
record.setSettFeeAmount(feePair.right);
record.setSettAmount(record.getApplyAmount() - record.getSettFeeAmount());
if(record.getApplyAmount() <= 0 || record.getSettFeeAmount() < 0 || record.getSettAmount() <= 0){
throw new BizException(String.format("提现金额计算错误! 申请: %s元 手续费%s元 到账:%s元",
AmountUtil.convertCent2Dollar(record.getApplyAmount()),
AmountUtil.convertCent2Dollar(record.getSettFeeAmount()),
AmountUtil.convertCent2Dollar(record.getSettAmount())
));
}
// 结算账户信息
record.setSettAccountType(agentInfo.getSettAccountType());
// 结算人姓名: 优先取值运营平台设置的费率, 如果为空,那么取 服务商申请时填入的。
record.setSettAccountName(StringUtils.defaultIfEmpty(infoParams.getSettAccountName(), record.getContactName()));
record.setContactName(infoParams.getContactName());
record.setSettAccountBank(agentInfo.getSettAccountBank());
record.setSettAccountSubBank(agentInfo.getSettAccountSubBank());
record.setSettAccountNo(agentInfo.getSettAccountNo());
record.setSettAccountTelphone(infoParams.getContactTel());
// 发起提现
cashoutRecordService.settAmount(record);
return ApiRes.ok();
}
/**
* @author: xiaoyu
* @date: 2022/3/29 16:54
* @describe: 获取当前服务商费率
*/
@PreAuthorize("hasAuthority('ENT_CASHOUT_PAYWAY_FEE')")
@GetMapping("/paywayFee")
public ApiRes getPaywayFee() {
AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());
CashoutFee cashoutFee = null;
// 使用默认
if(agentInfo.getCashoutFeeRuleType() == 1){
cashoutFee = JSON.parseObject(sysConfigService.getById("castOutFeeRule").getConfigVal(), CashoutFee.class);
}else{
cashoutFee = JSON.parseObject(agentInfo.getCashoutFeeRule(), CashoutFee.class);
}
return ApiRes.ok(cashoutFee);
}
/** 统计 **/
@PreAuthorize("hasAuthority('ENT_CASHOUT_RECORD_COUNT')")
@GetMapping(value="/count")
public ApiRes count() {
CashoutRecord record = getObject(CashoutRecord.class);
record.setInfoId(getCurrentAgentNo());
Map<String, Object> result = cashoutRecordService.countByCashout(record);
return ApiRes.ok(result);
}
}

View File

@@ -0,0 +1,64 @@
package com.jeequan.jeepay.agent.ctrl.account;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.InfoAccountHistory;
import com.jeequan.jeepay.service.impl.InfoAccountHistoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 钱包流水
*
* @author xiaoyu
* @date 2022/3/23 14:20
*/
@RestController
@RequestMapping("/api/accountHistory")
public class InfoAccountHistoryController extends CommonCtrl {
@Autowired private InfoAccountHistoryService infoAccountHistoryService;
/**
* @author: xiaoyu
* @date: 2022/3/23 14:34
* @describe: 钱包流水
*/
@PreAuthorize("hasAuthority('ENT_ACCOUNT_HISTORY_LIST')")
@GetMapping
public ApiRes list() {
InfoAccountHistory history = getObject(InfoAccountHistory.class);
history.setInfoId(getCurrentAgentNo());
history.setInfoType(CS.SYS_ROLE_TYPE.AGENT);
IPage<InfoAccountHistory> pages = infoAccountHistoryService.listByPage(getIPage(), history);
return ApiRes.page(pages);
}
/**
* @author: xiaoyu
* @date: 2022/3/23 14:34
* @describe: 钱包流水详情
*/
@PreAuthorize("hasAuthority('ENT_ACCOUNT_HISTORY_DETAIL')")
@GetMapping("/{hid}")
public ApiRes detail(@PathVariable("hid") String hid) {
InfoAccountHistory history = infoAccountHistoryService.getById(hid);
if (history == null) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
if (!history.getInfoId().equals(getCurrentAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
return ApiRes.ok(history);
}
}

View File

@@ -0,0 +1,130 @@
package com.jeequan.jeepay.agent.ctrl.agentconfig;
import cn.hutool.core.codec.Base64;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.AgentConfig;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.ThirdAuthDataEntity;
import com.jeequan.jeepay.service.impl.AgentConfigService;
import com.jeequan.jeepay.service.impl.AgentInfoService;
import com.jeequan.jeepay.service.impl.ThirdAuthDataService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
/***
* 服务商配置
*
* @author terrfly
*
* @date 2022/5/24 11:12
*/
@RestController
@RequestMapping("/api/agentConfig")
public class AgentConfigController extends CommonCtrl {
@Autowired private AgentInfoService agentInfoService;
@Autowired private AgentConfigService agentConfigService;
@Autowired
private ThirdAuthDataService thirdAuthDataService;
@MethodLog(remark = "更改支付密码")
@PutMapping("/agentSipw")
public ApiRes updateSipw() {
String confirmPwd = Base64.decodeStr(getValStringRequired("confirmPwd"));
// 验证原密码
AgentInfo dbAgentInfo = agentInfoService.getById(getCurrentAgentNo());
if(StringUtils.isNotEmpty(dbAgentInfo.getSipw())){
//当前旧密码
String originalPwd = Base64.decodeStr(getValStringRequired("originalPwd"));
if(!new BCryptPasswordEncoder().matches(originalPwd, dbAgentInfo.getSipw())){
throw new BizException("原支付验证失败!");
}
}
AgentInfo agentInfo = new AgentInfo();
agentInfo.setAgentNo(getCurrentAgentNo());
agentInfo.setSipw(new BCryptPasswordEncoder().encode(confirmPwd));
agentInfoService.updateById(agentInfo);
return ApiRes.ok();
}
/** 是否设置了支付密码 **/
@GetMapping("/hasSipwValidate")
public ApiRes hasSipwValidate() {
AgentInfo dbAgentInfo = agentInfoService.getById(getCurrentAgentNo());
return ApiRes.ok(StringUtils.isNotEmpty(dbAgentInfo.getSipw()));
}
/** 验证支付密码是否正确 **/
@PostMapping("/agentSipwValidate")
public ApiRes agentSipwValidate() {
//当前旧密码
String originalPwd = Base64.decodeStr(getValStringRequired("originalPwd"));
// 验证原密码
AgentInfo dbAgentInfo = agentInfoService.getById(getCurrentAgentNo());
return ApiRes.ok(StringUtils.isEmpty(dbAgentInfo.getSipw()) || new BCryptPasswordEncoder().matches(originalPwd, dbAgentInfo.getSipw()));
}
/**
* 根据configKey查询服务商配置
*/
@GetMapping("/{configKey}")
public ApiRes get(@PathVariable("configKey") String configKey) {
AgentConfig config = agentConfigService.getByAgentNoAndConfigKey(getCurrentAgentNo(), configKey);
return ApiRes.ok(config);
}
@PostMapping("/authData")
public ApiRes addAuthData() {
ThirdAuthDataEntity entity = getObject(ThirdAuthDataEntity.class);
Assert.notNull(entity.getType(), "授权渠道[type]不能为空");
Assert.notNull(entity.getSubType(), "授权类型[subType]不能为空");
Assert.notNull(entity.getAuthFileName(), "文件名称[authFileName]不能为空");
Assert.notNull(entity.getValue(), "文件内容[value]不能为空");
ThirdAuthDataEntity one = thirdAuthDataService.lambdaQuery()
.eq(ThirdAuthDataEntity::getAuthFileName, entity.getAuthFileName())
.one();
if (one != null) {
throw new BizException("数据已存在");
}
thirdAuthDataService.save(entity);
return ApiRes.ok();
}
@PostMapping("/config")
public ApiRes setConfig() {
AgentConfig reqParam = getObject(AgentConfig.class);
Assert.notNull(reqParam, "缺少参数");
Assert.notNull(reqParam.getGroupKey(), "配置分组名称代码[groupKey]不能为空");
Assert.notNull(reqParam.getConfigKey(), "配置名称代码[configKey]不能为空");
Assert.notNull(reqParam.getAgentNo(), "服务商编号[agentNo]不能为空");
Assert.notNull(reqParam.getConfigVal(), "配置项[configVal]未赋值");
agentConfigService.saveOrUpdateConfig(reqParam);
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,153 @@
package com.jeequan.jeepay.agent.ctrl.anon;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.agent.service.AuthService;
import com.jeequan.jeepay.bizcommons.manage.auth.AuthByQrcodeManage;
import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.cache.RedisUtil;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.jwt.JWTPayload;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.utils.JsonKit;
import org.apache.commons.lang3.StringUtils;
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.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* 登录鉴权
*
* @author terrfly
* @date 2021-04-27 15:50
*/
@RestController
@RequestMapping("/api/anon/auth")
public class AuthController extends CommonCtrl {
@Autowired private AuthService authService;
@Autowired private SmsManager smsManager;
/** 用户信息认证 获取iToken **/
@RequestMapping(value = "/validate", method = RequestMethod.POST)
@MethodLog(remark = "登录认证")
public ApiRes validate() throws BizException {
String loginPageType = Base64.decodeStr(getValStringRequired("lt")); //登录页面(终端)类型, 已做base64处理
// 是否app登录
boolean isApp = loginPageType.equals(JWTPayload.LOGIN_PAGE_TYPE.APP) || loginPageType.equals(JWTPayload.LOGIN_PAGE_TYPE.LITE);
String account = Base64.decodeStr(getValStringRequired("ia")); //用户名 i account, 已做base64处理
String ipassport = Base64.decodeStr(getValStringRequired("ip")); //密码 i passport, 已做base64处理
String vercode = isApp ? "" : Base64.decodeStr(getValStringRequired("vc")); // 验证码 vercode, 已做base64处理
String vercodeToken = isApp ? "" : Base64.decodeStr(getValStringRequired("vt")); //验证码token, vercode token , 已做base64处理
String mfaCode = StringUtils.isEmpty(getValString("mc")) ? null : Base64.decodeStr(getValString("mc")); // MFACode, 已做base64处理
// 验证码校验: WEB登录 & 第一次认证MFACode为空的情况
if(!isApp && StringUtils.isEmpty(mfaCode)){
String cacheCode = RedisUtil.getString(CS.getCacheKeyImgCode(vercodeToken));
if(StringUtils.isEmpty(cacheCode) || !cacheCode.equalsIgnoreCase(vercode)){
throw new BizException("验证码有误!");
}
}
// 返回前端 accessToken
return authService.authByAuthentication(account, ipassport, loginPageType, vercodeToken, mfaCode);
}
/** 用户信息认证[手机验证码登录] 获取iToken **/
@RequestMapping(value = "/phoneCode", method = RequestMethod.POST)
@MethodLog(remark = "手机验证码登录")
public ApiRes phoneCode() throws BizException {
String loginPageType = Base64.decodeStr(getValStringRequired("lt")); //登录页面(终端)类型, 已做base64处理
String phone = Base64.decodeStr(getValStringRequired("phone")); // 手机号, 已做base64处理
String code = Base64.decodeStr(getValStringRequired("code")); // 验证码 code, 已做base64处理
// 校验验证码 && 如果有异常 抛异常
smsManager.checkSmsVercodeThrowBizEx(phone, code, CS.SMS_TYPE_API_ENUM.TYPE_AUTH);
// 返回前端 accessToken
return authService.authByPhoneCode(phone, loginPageType);
}
/** 图片验证码 **/
@RequestMapping(value = "/vercode", method = RequestMethod.GET)
public ApiRes vercode() throws BizException {
//定义图形验证码的长和宽 // 4位验证码
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(137, 40, 4, 80);
lineCaptcha.createCode(); //生成code
//redis
String vercodeToken = UUID.fastUUID().toString();
RedisUtil.setString(CS.getCacheKeyImgCode(vercodeToken), lineCaptcha.getCode(), CS.VERCODE_CACHE_TIME ); //图片验证码缓存时间: 1分钟
JSONObject result = new JSONObject();
result.put("imageBase64Data", lineCaptcha.getImageBase64Data());
result.put("vercodeToken", vercodeToken);
result.put("expireTime", CS.VERCODE_CACHE_TIME);
return ApiRes.ok(result);
}
/** 轮询 登录二维码状态 **/
@GetMapping("/qrcodeStatus")
public ApiRes qrcodeStatus() {
String qrcodeNo = getValString("qrcodeNo");
// 未传入qrcodeNo直接返回一个并存入rediskeyJEEPAY_LOGIN_QR_qrcodeNo
if (StringUtils.isBlank(qrcodeNo)) {
qrcodeNo = CS.getCacheKeyLoginQrcode(IdUtil.simpleUUID());
AuthByQrcodeManage.setQrcodeStatusWaiting(qrcodeNo);
return ApiRes.ok(JsonKit.newJson("qrcodeNo", qrcodeNo));
}
// 根据传入的qrcodeNo判断二维码被扫状态
String qrCodeStatus = RedisUtil.getString(qrcodeNo);
// redis未查询到qrcodeNo信息
if (StringUtils.isBlank(qrCodeStatus)) {
return ApiRes.ok(JsonKit.newJson("qrcodeStatus", AuthByQrcodeManage.QRCODE_STATUS_EXPRIED));
}
JSONObject resJSON = new JSONObject();
if (qrCodeStatus.startsWith(AuthByQrcodeManage.QRCODE_STATUS_CONFIRMED + "_")){
String tokenStr = qrCodeStatus.replaceFirst(AuthByQrcodeManage.QRCODE_STATUS_CONFIRMED + "_", "");
resJSON = JSONObject.parseObject(tokenStr);
resJSON.put("qrcodeStatus", AuthByQrcodeManage.QRCODE_STATUS_CONFIRMED);
// 清空二维码缓存
AuthByQrcodeManage.delQrcodeStatus(qrcodeNo);
}else if (qrCodeStatus.equals(AuthByQrcodeManage.QRCODE_STATUS_CANCELED)){
resJSON.put("qrcodeStatus", AuthByQrcodeManage.QRCODE_STATUS_CANCELED);
// 清空二维码缓存
AuthByQrcodeManage.delQrcodeStatus(qrcodeNo);
}else {
resJSON.put("qrcodeStatus", qrCodeStatus);
}
return ApiRes.ok(resJSON);
}
}

View File

@@ -0,0 +1,110 @@
package com.jeequan.jeepay.agent.ctrl.anon;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.SysClientVersion;
import com.jeequan.jeepay.service.impl.SysClientVersionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 版本管理
*
* @author xiaoyu
* @date 2021/12/31 11:11
*/
@Slf4j
@RestController
@RequestMapping("/api/anon/clientVersion")
public class ClientVersionController extends CommonCtrl {
@Autowired private SysClientVersionService sysClientVersionService;
/**
* @author: xiaoyu
* @date: 2021/12/31 11:28
* @describe: 版本信息
*/
@RequestMapping(value = "/versionInfo", method = RequestMethod.GET)
public ApiRes versionInfo() {
// 版本号
String versionNumber = getValStringRequired("versionNumber");
SysClientVersion dbClientVersion = sysClientVersionService.getOne(
SysClientVersion.gw()
.eq(SysClientVersion::getClientType, SysClientVersion.CLIENT_TYPE_AGENT)
.eq(SysClientVersion::getVersionSerialNumber, versionNumber)
);
//未查询到当前版本信息, 查询最新版本作为 需[强制更新] 的版本
if(dbClientVersion == null){
List<SysClientVersion> newVersionList = sysClientVersionService.page(
new Page<>(1, 1),
new QueryWrapper<SysClientVersion>().lambda().eq(SysClientVersion:: getClientType, SysClientVersion.CLIENT_TYPE_AGENT).orderByDesc(SysClientVersion:: getVersionId)
).getRecords();
if(newVersionList != null && !newVersionList.isEmpty()){
SysClientVersion newVersion = newVersionList.get(0);
newVersion.setForceUpdate(CS.YES);
return ApiRes.ok(newVersion);
}else{
//未查询到 任何版本信息
return ApiRes.ok(new JSONObject());
}
}
// 查询到当前版本信息, 需查询当前版本之后的最新版本信息
List<SysClientVersion> newVersionList = sysClientVersionService.page(
new Page<>(1, 1),
new QueryWrapper<SysClientVersion>().lambda()
.eq(SysClientVersion:: getClientType, SysClientVersion.CLIENT_TYPE_AGENT)
.gt(SysClientVersion:: getVersionId, dbClientVersion.getVersionId())
.orderByDesc(SysClientVersion:: getVersionId)
).getRecords();
if(newVersionList == null || newVersionList.isEmpty()){
//未查询到 任何版本信息
return ApiRes.ok(new JSONObject());
}
//最新版本信息
SysClientVersion newVersion = newVersionList.get(0);
//如果当前版本前,包含强制更新, 则更改当前版本为强制更新版本
long count = sysClientVersionService.count(
new QueryWrapper<SysClientVersion>().lambda()
.eq(SysClientVersion:: getClientType, SysClientVersion.CLIENT_TYPE_AGENT)
.eq(SysClientVersion:: getForceUpdate, CS.YES)
.gt(SysClientVersion:: getVersionId, dbClientVersion.getVersionId())
);
if(count > 0){
newVersion.setForceUpdate(CS.YES);
}
return ApiRes.ok(newVersion);
}
/**
* @author: yr
* @date: 2023/02/10 16:20
* @describe: 服务商App获取最新版下载url
*/
@RequestMapping(value = "/downloadUrl", method = RequestMethod.GET)
public ApiRes downloadUrl() {
LambdaQueryWrapper<SysClientVersion> wrapper = SysClientVersion.gw();
wrapper.eq(SysClientVersion::getClientType, SysClientVersion.CLIENT_TYPE_AGENT);
if (sysClientVersionService.count(wrapper) == 0){
return ApiRes.ok();
}
wrapper.orderByDesc(SysClientVersion::getVersionId);
wrapper.last("limit 1");
return ApiRes.ok(sysClientVersionService.getOne(wrapper).getDownloadUrl());
}
}

View File

@@ -0,0 +1,51 @@
package com.jeequan.jeepay.agent.ctrl.anon;
import cn.hutool.core.codec.Base64;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 服务商注册
*
* @author xiaoyu
* @date 2021/12/30 14:59
*/
@RestController
@RequestMapping("/api/anon/register")
public class RegisterController extends CommonCtrl {
@Autowired private SmsManager smsManager;
/** 服务商注册接口 **/
@PostMapping(value = "/agentRegister")
@MethodLog(remark = "服务商注册")
public ApiRes retrieve() throws BizException {
// 服务商名称, 已做base64处理
String agentName = getValStringRequired("agentName");
// 手机号, 已做base64处理
String phone = Base64.decodeStr(getValStringRequired("phone"));
// 验证码, 已做base64处理
String code = Base64.decodeStr(getValStringRequired("code"));
// 确认密码 confirmPassword, 已做base64处理
String confirmPwd = Base64.decodeStr(getValStringRequired("confirmPwd"));
// 邀请码
String inviteCode = getValString("inviteCode");
// 校验验证码 && 如果有异常 抛异常
smsManager.checkSmsVercodeThrowBizEx(phone, code, CS.SMS_TYPE_API_ENUM.TYPE_REGISTER);
// 注册服务商
agentInfoService.mchRegister(phone, confirmPwd, agentName, inviteCode);
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,82 @@
package com.jeequan.jeepay.agent.ctrl.anon;
import cn.hutool.core.codec.Base64;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.DBsecurityConfig;
import com.jeequan.jeepay.db.entity.SysUserEntity;
import com.jeequan.jeepay.service.impl.SysConfigService;
import com.jeequan.jeepay.service.impl.SysUserAuthService;
import com.jeequan.jeepay.service.impl.SysUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/*
* 登录密码接口
*
* @author xiaoyu
* @date 2021/6/8 17:09
*/
@RestController
@RequestMapping("/api/anon/cipher")
public class RetrieveController extends CommonCtrl {
@Autowired private SysUserService sysUserService;
@Autowired private SysUserAuthService sysUserAuthService;
@Autowired private SysConfigService sysConfigService;
@Autowired private SmsManager smsManager;
/** 密码找回接口 **/
@RequestMapping(value = "/retrieve", method = RequestMethod.POST)
@MethodLog(remark = "密码找回")
public ApiRes retrieve() throws BizException {
// 手机号, 已做base64处理
String phone = Base64.decodeStr(getValStringRequired("phone"));
// 验证码, 已做base64处理
String code = Base64.decodeStr(getValStringRequired("code"));
// 新密码 password, 已做base64处理
String newPwd = Base64.decodeStr(getValString("newPwd"));
// 验证手机号
smsManager.checkSmsVercodeThrowBizEx(phone, code, CS.SMS_TYPE_API_ENUM.TYPE_RETRIEVE);
SysUserEntity dbUser = sysUserService.getOne(SysUserEntity.gw().eq(SysUserEntity::getTelphone, phone).eq(SysUserEntity::getSysType, CS.SYS_ROLE_TYPE.AGENT));
if (dbUser == null) {
throw new BizException("用户不存在");
}
if (StringUtils.isNotEmpty(newPwd)) {
// 更新用户登录密码
sysUserAuthService.resetAuthInfo(dbUser.getSysUserId(), null, null, true, newPwd, CS.SYS_ROLE_TYPE.AGENT);
// TODO mq更新用户密码
}
return ApiRes.ok();
}
/** 获取密码校验规则正则 **/
@RequestMapping(value = "/pwdRulesRegexp", method = RequestMethod.GET)
public ApiRes getPwdRulesRegexp() throws BizException {
DBsecurityConfig.PasswordRegexp passwordRegexp = sysConfigService.getDBSecurityConfig().getPasswordRegexp();
JSONObject resultJson = null;
if (passwordRegexp != null) {
resultJson = (JSONObject) JSONObject.toJSON(passwordRegexp);
// 查询是否需要审核
String subIsAudit = sysConfigService.getDBDefaultConfig().getAgentNewSubIsAudit();
resultJson.put("subIsAudit", subIsAudit);
}
return ApiRes.ok(resultJson);
}
}

View File

@@ -0,0 +1,80 @@
package com.jeequan.jeepay.agent.ctrl.anon;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.DBOEMConfig;
import com.jeequan.jeepay.core.service.ISysConfigService;
import com.jeequan.jeepay.core.utils.JsonKit;
import com.jeequan.jeepay.db.entity.AgentConfig;
import com.jeequan.jeepay.service.impl.AgentConfigService;
import com.jeequan.jeepay.service.impl.SysAdvertConfigService;
import com.jeequan.jeepay.service.impl.SysConfigService;
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;
/**
* 网站信息ctrl
*
* @author terrfly
* @date 2022/2/14 20:56
*/
@RestController
@RequestMapping("/api/anon/siteInfos")
public class SiteInfoController extends CommonCtrl {
@Autowired
private ISysConfigService sysConfigService;
@Autowired
private SysAdvertConfigService advertConfigService;
@Autowired
private AgentConfigService agentConfigService;
@GetMapping(value = "")
public ApiRes getSiteInfos() throws BizException {
JSONObject result = new JSONObject();
result.put("sysConfig", JsonKit.newJson("httpMsgIsEncrypt", SysConfigService.HTTP_MSG_IS_ENCRYPT));
DBOEMConfig dboemConfig = sysConfigService.getOemConfig();
//获取域名
String headerDomainName = getdomainName();
if (headerDomainName != null && headerDomainName.contains("//")) {
int startIndex = headerDomainName.indexOf("//") + 2; // 获取第一个 "//" 后的位置
int endIndex = headerDomainName.indexOf("/", startIndex); // 获取从 startIndex 开始的第一个 "/"
if (endIndex != -1) {
String domainName = headerDomainName.substring(startIndex, endIndex);
result.put("domainName", domainName);
AgentConfig agentConfig = agentConfigService.getOne(AgentConfig.gw().eq(AgentConfig::getGroupKey, "agentSiteConfig").eq(AgentConfig::getConfigVal, domainName).last("limit 1"));
if (agentConfig == null) {
//该域名没配置,取总后台数据
result.put("siteInfo", dboemConfig);
return ApiRes.ok(result);
}
//获取商户域名
AgentConfig mchDomainName = agentConfigService.getOne(AgentConfig.gw().eq(AgentConfig::getGroupKey, "agentSiteConfig").eq(AgentConfig::getConfigKey, "mchSiteUrl").eq(AgentConfig::getAgentNo, agentConfig.getAgentNo()));
if (mchDomainName != null) {
result.put("mchDomainName", mchDomainName.getConfigVal());
}
//获取服务商域名
AgentConfig agentDomainName = agentConfigService.getOne(AgentConfig.gw().eq(AgentConfig::getGroupKey, "agentSiteConfig").eq(AgentConfig::getConfigKey, "agentSiteUrl").eq(AgentConfig::getAgentNo, agentConfig.getAgentNo()));
if (mchDomainName != null) {
result.put("agentDomainName", agentDomainName.getConfigVal());
}
AgentConfig oemConfig = agentConfigService.getOne(AgentConfig.gw().eq(AgentConfig::getConfigKey, "oemConfig").eq(AgentConfig::getAgentNo, agentConfig.getAgentNo()));
if (oemConfig == null) {
//贴牌数据为空,取总后台数据
result.put("siteInfo", dboemConfig);
return ApiRes.ok(result);
}
result.put("siteInfo", JSONObject.parseObject(oemConfig.getConfigVal()));
}
}
return ApiRes.ok(result);
}
}

View File

@@ -0,0 +1,75 @@
package com.jeequan.jeepay.agent.ctrl.anon;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager;
import com.jeequan.jeepay.core.cache.RedisUtil;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.SysUserEntity;
import com.jeequan.jeepay.service.impl.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/*
* 短信验证
*
* @author xiaoyu
* @date 2021/6/8 17:09
*/
@RestController
@RequestMapping("/api/anon/sms")
public class SmsCodeController extends CommonCtrl {
@Autowired
private SysUserService sysUserService;
@Autowired
private SmsManager smsManager;
/**
* 发送短信验证码
**/
@RequestMapping(value = "/code", method = RequestMethod.POST)
public ApiRes code() throws BizException {
// 验证参数 手机号, 已做base64处理
String phone = getValStringRequired("phone");
String smsType = getValStringRequired("smsType");
String vercodeToken = getValStringRequired("vercodeToken");
String vercode = getValStringRequired("vercode");
String redisVercode = RedisUtil.getString(CS.getCacheKeyImgCode(vercodeToken));
if (!vercode.equalsIgnoreCase(redisVercode)) {
throw new BizException("验证码错误");
}
// 校验用户
checkUser(phone, smsType);
// 发送短信
smsManager.sendSmsVercode(phone, smsType);
return ApiRes.ok();
}
/**
* @author: xiaoyu
* @date: 2022/1/14 9:01
* @describe: 校验用户是否存在
*/
private void checkUser(String phone, String smsType) {
SysUserEntity dbUser = sysUserService.getOne(SysUserEntity.gw().eq(SysUserEntity::getTelphone, phone).eq(SysUserEntity::getSysType, CS.SYS_ROLE_TYPE.AGENT));
if (CS.SMS_TYPE_API_ENUM.TYPE_REGISTER.equals(smsType)) {
if (dbUser != null) {
throw new BizException("当前用户已存在");
}
} else {
if (dbUser == null) {
throw new BizException("用户不存在");
}
}
}
}

View File

@@ -0,0 +1,64 @@
package com.jeequan.jeepay.agent.ctrl.anon;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.AgentConfig;
import com.jeequan.jeepay.service.impl.AgentConfigService;
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 java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 服务政策 隐私协议ctrl
*
* @author xiaoyu
* @date 2022/2/16 14:51
*/
@RestController
@RequestMapping("/api/anon/treaty")
public class TreatyController extends CommonCtrl {
@Autowired private AgentConfigService agentConfigService;
@GetMapping(value = "")
public ApiRes getTreaty() throws BizException {
Map<String,Object> result = new HashMap<>();
//获取域名
String headerDomainName = getdomainName();
if (headerDomainName != null && headerDomainName.contains("//")) {
int startIndex = headerDomainName.indexOf("//") + 2; // 获取第一个 "//" 后的位置
int endIndex = headerDomainName.indexOf("/", startIndex); // 获取从 startIndex 开始的第一个 "/"
if (endIndex != -1) {
String domainName = headerDomainName.substring(startIndex, endIndex);
AgentConfig agentConfig = agentConfigService.getOne(AgentConfig.gw().eq(AgentConfig::getGroupKey, "agentSiteConfig")
.eq(AgentConfig::getConfigVal,domainName)
.last("limit 1"));
if (agentConfig == null){
//该域名没配置,取总后台数据
return ApiRes.ok(sysConfigService.getTreatyConfig());
}
List<AgentConfig> treatyConfigList = agentConfigService.list(AgentConfig.gw().eq(AgentConfig::getGroupKey, "treatyConfig")
.eq(AgentConfig::getAgentNo,agentConfig.getAgentNo()));
if(treatyConfigList.isEmpty()){
//贴牌数据为空,取总后台数据
return ApiRes.ok(sysConfigService.getTreatyConfig());
}else {
for (AgentConfig config : treatyConfigList) {
result.put(config.getConfigKey(), config.getConfigVal());
}
return ApiRes.ok(result);
}
}
}
return ApiRes.ok(sysConfigService.getTreatyConfig());
}
}

View File

@@ -0,0 +1,34 @@
package com.jeequan.jeepay.agent.ctrl.applyment;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.DBDefaultConfig;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 系统默认配置
*
* @author xiaoyu
*
* @date 2023/4/11 9:38
*/
@RestController
@RequestMapping("/api/defaultConfig")
public class DefaultConfigController extends CommonCtrl {
/** 平台默认配置查询 **/
@GetMapping("")
public ApiRes getDefaultConfig() {
JSONObject result = new JSONObject();
// 进件图片大小默认配置
DBDefaultConfig defaultConfig = sysConfigService.getDBDefaultConfig();
result.put("applymentImgUploadSize", defaultConfig.getApplymentImgUploadSize());
return ApiRes.ok(result);
}
}

View File

@@ -0,0 +1,54 @@
package com.jeequan.jeepay.agent.ctrl.applyment;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.converter.MchInfoConverter;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.MchApplyment;
import com.jeequan.jeepay.service.impl.MchApplymentService;
import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayMchApplymentService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
@RequestMapping("/api/mchApplyments")
public class KqpayMchApplymentController extends CommonCtrl {
@Autowired
private MchApplymentService mchApplymentService;
@Autowired
private KqpayMchApplymentService kqpayMchApplymentService;
@Autowired
private MchInfoConverter mchInfoConverter;
@PostMapping("/kqSignApply/{recordId}")
public ApiRes signApply(@PathVariable("recordId") String recordId) {
MchApplyment dbRecord = mchApplymentService.getById(recordId);
if (dbRecord == null || dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN) {
throw new BizException("请刷新当前申请单状态,该申请单当前状态无法执行该操作。");
}
com.jeequan.jeepay.core.entity.MchApplyment mchApplyment = kqpayMchApplymentService.signApply(mchInfoConverter.toModel(dbRecord));
MchApplyment applymentResult = new MchApplyment();
BeanUtils.copyProperties(mchApplyment, applymentResult);
// 当状态发生了变化时
if (!dbRecord.getState().equals(applymentResult.getState())) {
// 更新数据
applymentResult.setApplyId(recordId);
applymentResult.setLastApplyAt(new Date());
mchApplymentService.updateById(applymentResult);
}
return ApiRes.ok(applymentResult);
}
}

View File

@@ -0,0 +1,38 @@
package com.jeequan.jeepay.agent.ctrl.applyment;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/api/mchApplyments")
public class LklspayMchApplymentController {
/** 拉卡拉获取银行信息列表 **/
@GetMapping("/getLklBankList/{areaCode}/{branchName}")
public ApiRes getLklBankList(@PathVariable("areaCode") String areaCode, @PathVariable("branchName") String branchName) {
HttpResponse httpResponse = null;
try {
String result = null;
if (StringUtils.isNotEmpty(areaCode)) {
httpResponse = HttpRequest.get("https://tkapi.lakala.com/registration/bank?areaCode=" + areaCode + "&bankName=" + branchName).execute();
result = httpResponse.body();
}
return ApiRes.ok(result);
} catch (Exception e) {
throw new BizException(e.getMessage());
} finally {
if (httpResponse != null) {
httpResponse.close();
}
}
}
}

View File

@@ -0,0 +1,282 @@
package com.jeequan.jeepay.agent.ctrl.applyment;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.components.mq.model.MchAuditThirdNotifyMQ;
import com.jeequan.jeepay.components.mq.vender.IMQSender;
import com.jeequan.jeepay.converter.MchInfoConverter;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchModifyApplyment;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.interfaces.paychannel.IYsApplymentApiService;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.utils.JeepayKit;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.db.entity.MchAppEntity;
import com.jeequan.jeepay.db.entity.MchApplyment;
import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity;
import com.jeequan.jeepay.service.impl.MchAppService;
import com.jeequan.jeepay.service.impl.MchApplymentService;
import com.jeequan.jeepay.service.impl.MchModifyApplymentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/api/mchApplyments")
public class YspayMchApplymentController extends CommonCtrl {
@Autowired private MchApplymentService mchApplymentService;
@Autowired private MchModifyApplymentService mchModifyApplymentService;
@Autowired private MchAppService mchAppService;
@Autowired private MchInfoConverter mchInfoConverter;
@Autowired private IMQSender mqSender;
/** 银盛 上传图片 **/
@PostMapping("/yspayUpload/{recordId}")
public ApiRes yspayUpload(@PathVariable("recordId") String recordId) {
JSONObject paramJSON = getReqParamJSON();
MchApplyment dbRecord = mchApplymentService.getById(recordId);
if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_AUDITING && dbRecord.getState() != MchApplyment.STATE_WAIT_VERIFY &&
dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN && dbRecord.getState() != MchApplyment.STATE_FINISH_SIGN)) {
throw new BizException("当前申请单状态错误,无法继续。");
}
IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IYsApplymentApiService.class);
String respJSONStr = "";
try {
// 更新参数
dbRecord.setApplyDetailInfo(paramJSON.toJSONString());
// 调起接口
com.jeequan.jeepay.core.entity.MchApplyment mchApplymentImg = ysApplymentApiService.uploadImg(mchInfoConverter.toModel(dbRecord));
respJSONStr = mchApplymentImg.getChannelVar1();
MchApplyment updateRecord = new MchApplyment();
updateRecord.setApplyDetailInfo(dbRecord.getApplyDetailInfo());
BeanUtils.copyProperties(mchApplymentImg, updateRecord);
// 更新数据
updateRecord.setApplyId(recordId);
mchApplymentService.updateById(updateRecord);
} catch (BizException e) {
logger.info("请求异常", e);
throw e;
}
return ApiRes.ok(respJSONStr);
}
/** 银盛 资料确认 **/
@PostMapping("/yspayConfirm/{recordId}")
public ApiRes yspayConfirm(@PathVariable("recordId") String recordId) {
MchApplyment dbRecord = mchApplymentService.getById(recordId);
if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_AUDITING && dbRecord.getState() != MchApplyment.STATE_WAIT_VERIFY &&
dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN && dbRecord.getState() != MchApplyment.STATE_FINISH_SIGN)) {
throw new BizException("当前申请单状态错误,无法继续。");
}
IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IYsApplymentApiService.class);
String respJSONStr = "";
try {
// 提交审核
com.jeequan.jeepay.core.entity.MchApplyment applymentResult = ysApplymentApiService.attachConfirm(mchInfoConverter.toModel(dbRecord));
respJSONStr = applymentResult.getApplyErrorInfo();
MchApplyment updateRecordAudit = new MchApplyment();
BeanUtils.copyProperties(applymentResult, updateRecordAudit);
// 更新数据
updateRecordAudit.setApplyId(recordId);
mchApplymentService.updateById(updateRecordAudit);
} catch (BizException e) {
logger.info("请求异常", e);
throw e;
}
return ApiRes.ok(respJSONStr);
}
/** 银盛 发起合同签约 **/
@PostMapping("/ysSignApply/{recordId}")
public ApiRes ysSignApply(@PathVariable("recordId") String recordId) {
MchApplyment dbRecord = mchApplymentService.getById(recordId);
if (dbRecord == null || dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN) {
throw new BizException("请刷新当前申请单状态,该申请单当前状态无法执行该操作。");
}
IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IYsApplymentApiService.class);
// 调起接口
com.jeequan.jeepay.core.entity.MchApplyment applymentResult = ysApplymentApiService.signApply(getReqParamJSON(), mchInfoConverter.toModel(dbRecord));
// 更新商户费率配置
MchApplyment updateRecordAudit = new MchApplyment();
BeanUtils.copyProperties(applymentResult, updateRecordAudit);
// 更新数据
updateRecordAudit.setApplyId(recordId);
mchApplymentService.updateById(updateRecordAudit);
return ApiRes.ok(applymentResult.getChannelVar2());
}
/** 银盛 查询合同签约状态 **/
@PostMapping("/ysSignQuery/{recordId}")
public ApiRes ysSignQuery(@PathVariable("recordId") String recordId) {
MchApplyment dbRecord = mchApplymentService.getById(recordId);
if (dbRecord == null || dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN) {
throw new BizException("请刷新当前申请单状态,该申请单当前状态无法执行该操作。");
}
// 获取当前进件签约信息,未发起签约时为空
if (StringUtils.isBlank(dbRecord.getChannelVar2())) {
return ApiRes.ok();
}
IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(IYsApplymentApiService.class);
// 调起接口
com.jeequan.jeepay.core.entity.MchApplyment applymentResult = ysApplymentApiService.signQuery(mchInfoConverter.toModel(dbRecord));
// 更新商户费率配置
MchApplyment updateRecordAudit = mchInfoConverter.toDbEntity(applymentResult);
// 更新数据
updateRecordAudit.setApplyId(recordId);
mchApplymentService.updateById(updateRecordAudit);
if (updateRecordAudit.getState() == MchApplyment.STATE_SUCCESS) {
mchApplymentService.onApplymentSuccess(updateRecordAudit.getApplyId());
mqSender.send(MchAuditThirdNotifyMQ.build(recordId, MchAuditThirdNotifyMQ.TYPE_AUDIT));
}
return ApiRes.ok(applymentResult.getChannelVar2());
}
/** 银盛 签约重发 **/
@PostMapping("/ysSignSendAgain/{recordId}")
public ApiRes ysSignSendAgain(@PathVariable("recordId") String recordId) {
MchApplyment dbRecord = mchApplymentService.getById(recordId);
if (dbRecord == null) {
MchModifyApplymentEntity modifyApplyment = mchModifyApplymentService.getById(recordId);
if (modifyApplyment == null || modifyApplyment.getState() != MchApplyment.STATE_WAIT_SIGN) {
throw new BizException("请刷新当前申请单状态,该申请单当前状态无法执行该操作。");
}
IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(CS.IF_CODE.YSPAY + "ApplymentApiService", IYsApplymentApiService.class);
// 调起接口
MchModifyApplyment applymentResult = ysApplymentApiService.signSendAgain(getReqParamJSON(), mchInfoConverter.toModel(modifyApplyment));
// 更新数据
if (!StrUtil.isEmpty(applymentResult.getChannelVar1())) {
MchModifyApplymentEntity updateRecordAudit = new MchModifyApplymentEntity();
updateRecordAudit.setApplyId(recordId);
updateRecordAudit.setChannelVar1(applymentResult.getChannelVar1());
mchModifyApplymentService.updateById(updateRecordAudit);
}
return ApiRes.ok(applymentResult.getChannelVar1());
} else {
if (dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN) {
throw new BizException("请刷新当前申请单状态,该申请单当前状态无法执行该操作。");
}
IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(CS.IF_CODE.YSPAY + "ApplymentApiService", IYsApplymentApiService.class);
// 调起接口
com.jeequan.jeepay.core.entity.MchApplyment applymentResult = ysApplymentApiService.signSendAgain(getReqParamJSON(), mchInfoConverter.toModel(dbRecord));
// 更新数据
if (!StrUtil.isEmpty(applymentResult.getChannelVar2())) {
MchApplyment updateRecordAudit = new MchApplyment();
updateRecordAudit.setApplyId(recordId);
updateRecordAudit.setChannelVar2(applymentResult.getChannelVar2());
mchApplymentService.updateById(updateRecordAudit);
}
return ApiRes.ok(applymentResult.getChannelVar2());
}
}
/** 银盛费率配置 **/
@PostMapping("/ysPayRateConfig/{recordId}")
public ApiRes ysPayRateConfig(@PathVariable("recordId") String recordId) {
JSONObject reqParamJSON = getReqParamJSON();
MchApplyment dbRecord = mchApplymentService.getById(recordId);
if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_AUDITING && dbRecord.getState() != MchApplyment.STATE_REJECT_WAIT_MODIFY
&& dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN)) {
throw new BizException("请刷新当前申请单状态,该申请单当前状态无法执行该操作。");
}
IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IYsApplymentApiService.class);
// 调起接口
com.jeequan.jeepay.core.entity.MchApplyment applymentResult = ysApplymentApiService.payRateConfig(reqParamJSON, mchInfoConverter.toModel(dbRecord));
// 更新商户费率配置
MchApplyment updateRecordAudit = new MchApplyment();
// 配置成功更新费率
if (applymentResult.getState() != null && applymentResult.getState() == MchApplyment.STATE_SUCCESS) {
BeanUtils.copyProperties(applymentResult, updateRecordAudit);
} else {
applymentResult.setApplyDetailInfo(null);
applymentResult.setState(MchApplyment.STATE_AUDITING);
BeanUtils.copyProperties(applymentResult, updateRecordAudit);
}
// 更新数据
updateRecordAudit.setApplyId(recordId);
mchApplymentService.updateById(updateRecordAudit);
return ApiRes.ok(applymentResult.getChannelVar1());
}
/** 银盛 配置相关信息 **/
@PostMapping("/yspayInterfaceConfig/{applyId}/{mchAppId}")
public ApiRes yspayInterfaceConfig(@PathVariable("applyId") String applyId, @PathVariable("mchAppId") String mchAppId) {
String configType = getValStringRequired("configType"); // PAY_BASE_URL, BIND_APP_ID, SUBSCRIBE_APP_ID, QUERY
String configVal = getValStringRequired("configVal");
MchApplyment tbMchApplyment = mchApplymentService.getById(applyId);
MchAppEntity mchAppEntity = mchAppService.getById(mchAppId);
IYsApplymentApiService applymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(tbMchApplyment.getIfCode()) + "ApplymentApiService", IYsApplymentApiService.class);
if ("PAY_BASE_URL".equals(configType)) {
return ApiRes.ok(applymentApiService.configPayBaseUrl(configVal, mchAppEntity.getAppId(), mchInfoConverter.toModel(tbMchApplyment)));
} else if ("BIND_APP_ID".equals(configType)) {
return ApiRes.ok(applymentApiService.configBindAppId(configVal, mchAppEntity.getAppId(), mchInfoConverter.toModel(tbMchApplyment)));
} else if ("SUBSCRIBE_APP_ID".equals(configType)) {
return ApiRes.ok(applymentApiService.configSubscribeAppId(configVal, mchAppEntity.getAppId(), mchInfoConverter.toModel(tbMchApplyment)));
}
return ApiRes.customFail("没有[" + configType + "]配置");
}
}

View File

@@ -0,0 +1,395 @@
package com.jeequan.jeepay.agent.ctrl.aqf;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.response.AlipayFundAccountbookQueryResponse;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.cache.RedisUtil;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.TransferOrder;
import com.jeequan.jeepay.core.entity.TransferSubject;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.tranfer.TransferBasicInfo;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.service.impl.SysConfigService;
import com.jeequan.jeepay.service.impl.TransferSubjectService;
import com.jeequan.jeepay.service.impl.TransferWalletService;
import com.jeequan.jeepay.thirdparty.channel.alipay.AliAqfV2Service;
import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@RestController
@RequestMapping("/api/aqfApi")
public class AqfApiController extends CommonCtrl {
@Autowired
private AliAqfV2Service aliAqfV2Service;
@Autowired
private SysConfigService sysConfigService;
@Autowired
private TransferSubjectService transferSubjectService;
@Autowired
private ChannelCertConfigKitBean channelCertConfigKitBean;
@Autowired
private TransferWalletService transferWalletService;
/**
* 签约
*
* @return
*/
@RequestMapping(value = "/signUrl", method = RequestMethod.GET)
public ApiRes signUrl() {
String subId = getValStringRequired("subId");
String resutUrl = aliAqfV2Service.userAgreementPageSign(subId);
return ApiRes.ok(resutUrl);
}
/**
* 支付宝个人代扣协议查询接口
*
* @return
*/
@RequestMapping(value = "/agreementQuery" , method = RequestMethod.GET)
public ApiRes agreementQuery(){
String subId = getValStringRequired("subId");
JSONObject alipayUserAgreementQueryResponse = aliAqfV2Service.userAgreementQuery(subId);
return ApiRes.ok(alipayUserAgreementQueryResponse);
}
/**
* 解约
*
* @return
*/
@RequestMapping(value = "/userAgreementUnsign" , method = RequestMethod.GET)
public ApiRes userAgreementUnsign(){
String subId = getValStringRequired("subId");
JSONObject alipayUserAgreementUnsignResponse = aliAqfV2Service.userAgreementUnsign(subId);
return ApiRes.ok(alipayUserAgreementUnsignResponse);
}
/**
* 记账本查询
*
* @return
*/
@RequestMapping(value = "/alipayFundAccountbookQuery", method = RequestMethod.GET)
public ApiRes alipayFundAccountbookQuery() {
String subId = getValStringRequired("subId");
String walletApplyId = getValString("walletApplyId");
// 设计上,一个签约主体可以创建多个记账本,实际使用的时候,尽量保持一个签约主体只有一个账本
AlipayFundAccountbookQueryResponse alipayFundAccountbookQueryResponse = aliAqfV2Service.fundAccountbookQuery(walletApplyId);
return ApiRes.ok(JSON.parseObject(alipayFundAccountbookQueryResponse.getBody()).getJSONObject("alipay_fund_accountbook_query_response"));
}
/**
* 资金专款拨入(商户自身给记账本充值)
*
* @return
*/
@RequestMapping(value = "/transPage" , method = RequestMethod.GET)
public ApiRes transPage(){
String subId = getValStringRequired("subId");
String transAmount = getValStringRequired("transAmount");
String transferDesc = getValString("transferDesc");
String transedUrl = aliAqfV2Service.transPage(subId, transAmount,transferDesc);
return ApiRes.ok(transedUrl);
}
/**
* 单笔生成待发待结算信息
*
* @return
*/
@RequestMapping(value = "/settlementData", method = RequestMethod.POST)
public ApiRes settlementDate() {
String currentAgentNo = getCurrentAgentNo();
String transferSubjectIdFq = getValStringRequired("transferSubjectIdFq");
String vc = Base64.decodeStr(getValStringRequired("vc"));
String vt = Base64.decodeStr(getValStringRequired("vt"));
String sipw = Base64.decodeStr(getValStringRequired("sipw"));
// 验证码校验
String cacheCode = RedisUtil.getString(CS.getCacheKeyImgCode(vt));
if(StringUtils.isEmpty(cacheCode) || !cacheCode.equalsIgnoreCase(vc)){
throw new BizException("验证码有误!");
}
TransferSubjectEntity transferSubject = transferSubjectService.getById(transferSubjectIdFq);
if (!transferSubject.getInfoType().equals(CS.SYS_ROLE_TYPE.AGENT)
|| !currentAgentNo.equals(transferSubject.getAgentNo())) {
throw new BizException("非法操作");
}
AgentInfo agentInfo = agentInfoService.getById(transferSubject.getAgentNo());
if (!sipw.equals(agentInfo.getSipw())) {
throw new BizException("支付密码校验失败");
}
SettlementDataModel object = getObject(SettlementDataModel.class);
String date = aliAqfV2Service.settlementData(object.getTransferSubjectIdFq(), object.getTransferOrders());
return ApiRes.ok(date);
}
/**
* 批量生成待结算数据,先入库再发起结算
*/
@PostMapping("/batchSettlementData")
public ApiRes uploadExcel() {
String currentAgentNo = getCurrentAgentNo();
String transferSubjectIdFq = getValStringRequired("transferSubjectIdFq");
String excelFileName = getValStringRequired("excelFileName");
File excelFile = channelCertConfigKitBean.getCertFile(excelFileName);
SettlementDataModel params = getObject(SettlementDataModel.class);
String vc = Base64.decodeStr(getValStringRequired("vc"));
String vt = Base64.decodeStr(getValStringRequired("vt"));
String sipw = Base64.decodeStr(getValStringRequired("sipw"));
// 验证码校验
String cacheCode = RedisUtil.getString(CS.getCacheKeyImgCode(vt));
if(StringUtils.isEmpty(cacheCode) || !cacheCode.equalsIgnoreCase(vc)){
throw new BizException("验证码有误!");
}
TransferSubjectEntity transferSubject = transferSubjectService.getById(transferSubjectIdFq);
if (!transferSubject.getInfoType().equals(CS.SYS_ROLE_TYPE.AGENT)
|| !currentAgentNo.equals(transferSubject.getAgentNo())) {
throw new BizException("非法操作");
}
AgentInfo agentInfo = agentInfoService.getById(transferSubject.getAgentNo());
if (!sipw.equals(agentInfo.getSipw())) {
throw new BizException("支付密码校验失败");
}
List<SettleBatchExcel> dataList = new ArrayList<>();
List<TransferOrder> transferOrderList = new ArrayList<>();
String batch = "BATCH" + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6);
try {
InputStream inputStream = Files.newInputStream(excelFile.toPath());
EasyExcel.read(inputStream, SettleBatchExcel.class, new AnalysisEventListener<SettleBatchExcel>() {
@Override
public void invoke(SettleBatchExcel settleBatchExcel, AnalysisContext analysisContext) {
dataList.add(settleBatchExcel);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 解析完成后的操作,可以在这里进行一些清理工作
}
}).sheet().doRead();
//把数据新增到收款信息中
Assert.notEmpty(params.getTaskId(), "任务号不能为空");
TransferSubjectEntity sponsor = transferSubjectService.getById(params.getTransferSubjectIdFq());
if (!getCurrentAgentNo().equalsIgnoreCase(sponsor.getAgentNo())) {
throw new BizException("参数非法");
}
if (!Objects.equals(sponsor.getState(), TransferSubject.STATE_ENABLE)) {
throw new BizException("付款账户当前状态不可用");
}
if (!Objects.equals(sponsor.getSignState(), (int) TransferSubject.SIGN_STATE_SUCCESS)) {
throw new BizException("付款账户暂未完成签约");
}
TransferWalletEntity transferWallet = transferWalletService.getByApplyId(sponsor.getTransApplyId(), null);
String extCardInfo = transferWallet.getExtCardInfo();
JSONObject extCardJSON = JSONObject.parseObject(extCardInfo);
Assert.notNull(sponsor, "未获取到对应的转账发起方信息");
for (SettleBatchExcel settleBatchExcel : dataList) {
TransferSubjectEntity receiver = transferSubjectService.getReceiver(sponsor.getIsvNo(),
CS.IF_CODE.ALIAQF, CS.SYS_ROLE_TYPE.AGENT, getCurrentAgentNo(), settleBatchExcel.getAccountNo(),
settleBatchExcel.getEntryType(), settleBatchExcel.getAccountType());
if (receiver == null) {
// 先存储转账接受账户信息
receiver = new TransferSubjectEntity();
receiver.setId("SUB" + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6));
receiver.setAccount(settleBatchExcel.getAccountNo());
receiver.setState(TransferSubject.STATE_ENABLE);
receiver.setSubjectType(TransferSubject.SUBJECT_TYPE_RECEIVER);
receiver.setIsvNo(sponsor.getIsvNo());
receiver.setInfoType(sponsor.getInfoType());
receiver.setMchNo(sponsor.getMchNo());
receiver.setAgentNo(sponsor.getAgentNo());
receiver.setAgentName(sponsor.getAgentName());
receiver.setTopAgentNo(sponsor.getTopAgentNo());
receiver.setTransIfCode(sponsor.getTransIfCode());
receiver.setSignState(sponsor.getSignState());
receiver.setAccountName(settleBatchExcel.getAccountName());
receiver.setAccountType(settleBatchExcel.getAccountType());
receiver.setEntryType(settleBatchExcel.getEntryType());
transferSubjectService.save(receiver);
if (TransferBasicInfo.ENTRY_TYPE_BANK.equalsIgnoreCase(settleBatchExcel.getEntryType())) {
// 保存银联支行信息
JSONObject bankCardBranchInfo = new JSONObject();
if (settleBatchExcel.getInstCity() != null) {
bankCardBranchInfo.put("instName", settleBatchExcel.getInstName());
bankCardBranchInfo.put("instProvince", settleBatchExcel.getInstProvince());
bankCardBranchInfo.put("instCity", settleBatchExcel.getInstCity());
bankCardBranchInfo.put("instBranchName", settleBatchExcel.getInstBranchName());
}
receiver.setAccountMessage(bankCardBranchInfo.toJSONString());
}
}
// 保存一些订单信息
TransferOrder transferOrder = new TransferOrder();
transferOrder.setMchNo(sponsor.getMchNo());
transferOrder.setIsvNo(sponsor.getIsvNo());
transferOrder.setAgentNo(sponsor.getAgentNo());
transferOrder.setTransferSubjectIdFq(params.getTransferSubjectIdFq());
transferOrder.setTransferSubjectIdJs(receiver.getId());
transferOrder.setIfCode(receiver.getTransIfCode());
transferOrder.setWalletId(transferWallet.getId());
transferOrder.setEntryType(settleBatchExcel.getEntryType());
transferOrder.setAccountType(settleBatchExcel.getAccountType());
transferOrder.setAccountName(settleBatchExcel.getAccountName());
transferOrder.setAccountNo(settleBatchExcel.getAccountNo());
transferOrder.setOriginAccountNo(sponsor.getAccount());
transferOrder.setOriginAccountName(sponsor.getAccountName());
transferOrder.setBatchId(batch);
transferOrderList.add(transferOrder);
}
//新增或更新完毕后发起结算
aliAqfV2Service.settlementData(params.getTransferSubjectIdFq(), transferOrderList);
} catch (IOException e) {
logger.info("批量导入安全发代发数据解析失败!");
// 处理异常
}
// 对 dataList 进行后续操作,如存储到数据库等
return ApiRes.ok();
}
// /**
// * 代发到户 --不直接调用
// * @return
// */
// @RequestMapping(value = "/transUniTransfer" , method = RequestMethod.GET)
// public ApiRes transUniTransfer(){
// String ersubId = getValStringRequired("ersubId");
// String eesubId = getValStringRequired("eesubId");
// String transAmount = getValStringRequired("transAmount");
// String taskId = getValStringRequired("taskId");
// String transferDesc = getValString("transferDesc");
// AlipayFundTransUniTransferResponse alipayFundTransUniTransferResponse = aliAqfV2Service.transUniTransfer(ersubId, eesubId, getDefaultIsvConfig(), transAmount,taskId,null,transferDesc);
// return ApiRes.ok(alipayFundTransUniTransferResponse);
// }
// /**
// * 代发到卡 --不直接调用
// * @return
// */
// @RequestMapping(value = "/transUniTransferCard" , method = RequestMethod.GET)
// public ApiRes transUniTransferCard(){
// String ersubId = getValStringRequired("ersubId");
// String eesubId = getValStringRequired("eesubId");
// String transAmount = getValStringRequired("transAmount");
// String taskId = getValStringRequired("taskId");
// String transferDesc = getValString("transferDesc");
// AlipayFundTransUniTransferResponse alipayFundTransUniTransferResponse = aliAqfV2Service.transUniTransferCard(ersubId, eesubId, getDefaultIsvConfig(), transAmount, taskId,null,transferDesc);
// return ApiRes.ok(alipayFundTransUniTransferResponse);
// }
/**
* 账单查询
*
* @return
*/
@RequestMapping(value = "/bizfundagentQuery", method = RequestMethod.GET)
public ApiRes bizfundagentQuery() {
String ersubId = getValStringRequired("ersubId");
String startTime = getValStringRequired("startTime");
String endTime = getValStringRequired("endTime");
String pageNo = getValStringRequired("pageNo");
String pageSize = getValStringRequired("pageSize");
JSONObject alipayDataBillBizfundagentQueryResponse = aliAqfV2Service.bizfundagentQuery(ersubId, startTime, endTime, pageNo, pageSize);
return ApiRes.ok(alipayDataBillBizfundagentQueryResponse);
}
/**
* 电子回单申请
*
* @return
*/
@RequestMapping(value = "/applicationForm", method = RequestMethod.GET)
public ApiRes applicationForm() {
String ersubId = getValStringRequired("ersubId");
String transferId = getValStringRequired("transferId");
JSONObject alipayDataBillEreceiptagentApplyResponse = aliAqfV2Service.applicationForm(ersubId, transferId);
return ApiRes.ok(alipayDataBillEreceiptagentApplyResponse);
}
/**
* 电子回单下载地址获取
*
* @return
*/
@RequestMapping(value = "/applicationFormDownload", method = RequestMethod.GET)
public ApiRes applicationFormDownload() {
String ersubId = getValStringRequired("ersubId");
String transferId = getValStringRequired("transferId");
JSONObject alipayDataBillAccountbookereceiptQueryResponse = aliAqfV2Service.applicationFormDownload(ersubId, transferId);
return ApiRes.ok(alipayDataBillAccountbookereceiptQueryResponse);
}
public String getDefaultIsvConfig() {
SysConfig serviceOne = sysConfigService.getOne(SysConfig.gw().eq(SysConfig::getGroupKey, "defaultConfig")
.eq(SysConfig::getConfigKey, "defaultIsvNo"));
if (serviceOne != null) {
return serviceOne.getConfigVal();
}
return null;
}
/**
* 根据付款人信息id获取详情
*/
public TransferSubjectEntity getSubjectOne(String subId){
TransferSubjectEntity transferSubjectEntity = transferSubjectService.getById(subId);
if (transferSubjectEntity != null){
return transferSubjectEntity;
}else {
throw new BizException("未查询到当前付款人信息!");
}
}
}

View File

@@ -0,0 +1,214 @@
package com.jeequan.jeepay.agent.ctrl.aqf;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.entity.SysUser;
import com.jeequan.jeepay.core.entity.TransferSubject;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.MchInfo;
import com.jeequan.jeepay.db.entity.TransferSubjectEntity;
import com.jeequan.jeepay.service.impl.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
/**
* 转账对象信息
*/
@RestController
@RequestMapping("/api/aqf")
public class AqfController extends CommonCtrl {
@Autowired
private TransferSubjectService transferSubjectService;
@Autowired
private TransferInterfaceConfigService transferInterfaceConfigService;
@Autowired
private IsvInfoService isvInfoService;
@Autowired
private AgentInfoService agentInfoService;
@Autowired
private MchInfoService mchInfoService;
/**
* 新增付款方账户信息
*
* @return
*/
@RequestMapping(value = "/add", method = RequestMethod.POST)
public ApiRes addTransferSubject() {
TransferSubjectEntity transferSubject = getObject(TransferSubjectEntity.class);
// 当前登录用户信息
transferSubject.setId("SUB" + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6));
SysUser sysUser = getCurrentUser().getSysUser();
transferSubject.setSubjectType("FQ");
transferSubject.setTransApplyId(UUID.randomUUID().toString().replace("-", "").substring(0, 32));
//当前服务商
transferSubject.setAgentNo(getCurrentAgentNo());
//获取渠道信息
AgentInfo agentInfo = agentInfoService.getById(transferSubject.getAgentNo());
transferSubject.setIsvNo(agentInfo.getIsvNo());
transferSubject.setCreatedUid(sysUser.getSysUserId());
boolean save = transferSubjectService.save(transferSubject);
if (save) {
return ApiRes.ok();
} else {
return ApiRes.customFail("新增失败!");
}
}
/**
* 查询
*/
@GetMapping("/getPageList")
public ApiRes pageTransferSubject() {
TransferSubjectEntity transferSubject = getObject(TransferSubjectEntity.class);
// 时间搜索
Date[] searchDateRange = transferSubject.buildQueryDateRange();
transferSubject.setFirstDate(searchDateRange[0]);
transferSubject.setLastDate(searchDateRange[1]);
// 可查看自己和全部下级代理数据
String currentAgentNo = getCurrentAgentNo();
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
// 自己和下级服务商
if (CollUtil.isNotEmpty(subAgentNoList)){
transferSubject.setSubAgentNoList(subAgentNoList);
}
IPage<TransferSubjectEntity> pageList = transferSubjectService.getPageList(getIPage(), transferSubject);
return ApiRes.page(pageList);
}
/**
* 查询详情
*/
@GetMapping(value = "/{id}")
public ApiRes getByIdTransferSubject(@PathVariable("id") Integer id) {
TransferSubjectEntity byId = transferSubjectService.getById(id);
return ApiRes.ok(byId);
}
/**
* 修改
*/
@PutMapping(value = "/{id}")
public ApiRes updateTransferSubject(@PathVariable("id") String id) {
TransferSubjectEntity transferSubject = getObject(TransferSubjectEntity.class);
transferSubject.setId(id);
//当前服务商
transferSubject.setAgentNo(getCurrentAgentNo());
//获取渠道信息
AgentInfo agentInfo = agentInfoService.getById(transferSubject.getAgentNo());
transferSubject.setIsvNo(agentInfo.getIsvNo());
boolean resut = transferSubjectService.updateById(transferSubject);
if (resut) {
return ApiRes.ok();
} else {
return ApiRes.customFail("修改失败!");
}
}
/**
* 删除
*/
@DeleteMapping("/{id}")
public ApiRes deleteTransferSubject(@PathVariable("id") Integer id) {
boolean resut = transferSubjectService.removeById(id);
if (resut) {
return ApiRes.ok();
} else {
return ApiRes.customFail("删除失败!");
}
}
/**
* 新增收款方账户信息
*/
@PostMapping("/addJs")
public ApiRes addJsTransferSubject() {
TransferSubjectEntity transferSubject = getObject(TransferSubjectEntity.class);
// 当前登录用户信息
transferSubject.setId("SUB" + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6));
SysUser sysUser = getCurrentUser().getSysUser();
transferSubject.setSubjectType("JS");
transferSubject.setCreatedUid(sysUser.getSysUserId());
//当前服务商
transferSubject.setAgentNo(getCurrentAgentNo());
//获取渠道信息
AgentInfo agentInfo = agentInfoService.getById(transferSubject.getAgentNo());
transferSubject.setIsvNo(agentInfo.getIsvNo());
boolean save = transferSubjectService.save(transferSubject);
if (save) {
return ApiRes.ok();
} else {
return ApiRes.customFail("新增失败!");
}
}
@GetMapping("/getBatchData")
public ApiRes getBatchData() {
String transferSubjects = getValStringRequired("transferSubjects");
List<TransferSubjectEntity> transferSubjectEntityList = new ArrayList<>();
String[] transferSubjectSpli = transferSubjects.split(",");
for (String transferSubjectId : transferSubjectSpli) {
TransferSubjectEntity transferSubjectEntity = transferSubjectService.getById(transferSubjectId);
if (transferSubjectEntity != null) {
transferSubjectEntityList.add(transferSubjectEntity);
}
}
return ApiRes.ok(transferSubjectEntityList);
}
@PostMapping("/state")
public ApiRes exam() {
JSONObject reqParamJSON = getReqParamJSON();
Integer state = reqParamJSON.getInteger("state");
String id = reqParamJSON.getString("id");
String remark = reqParamJSON.getString("remark");
TransferSubjectEntity transferSubjectEntity = transferSubjectService.getById(id);
Assert.notNull(transferSubjectEntity, "付款账户信息不存在");
if (state == TransferSubject.STATE_DISABLE) {
transferSubjectEntity.setState(TransferSubject.STATE_DISABLE);
transferSubjectEntity.setRemark(remark);
transferSubjectService.updateById(transferSubjectEntity);
} else if (state == TransferSubject.STATE_ENABLE) {
transferSubjectEntity.setState(TransferSubject.STATE_ENABLE);
transferSubjectService.updateById(transferSubjectEntity);
} else if (state == TransferSubject.STATE_ENABLE_REVIEW) {
transferSubjectEntity.setState(TransferSubject.STATE_ENABLE_REVIEW);
transferSubjectService.updateById(transferSubjectEntity);
}
return ApiRes.ok();
}
/**
* 统计收款账户总成交金额和总成交笔数
*/
@GetMapping("/getSubStatistics")
public Map<String, Object> getSubStatistics(){
TransferSubjectEntity subject = getObject(TransferSubjectEntity.class);
// 可查看自己和全部下级代理数据
String currentAgentNo = getCurrentAgentNo();
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
// 自己和下级服务商
if (CollUtil.isNotEmpty(subAgentNoList)){
subject.setSubAgentNoList(subAgentNoList);
}
return transferSubjectService.getSubStatistics(subject);
}
}

View File

@@ -0,0 +1,120 @@
package com.jeequan.jeepay.agent.ctrl.aqf;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.entity.SysUser;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.MchInfo;
import com.jeequan.jeepay.db.entity.TaskList;
import com.jeequan.jeepay.service.impl.MchInfoService;
import com.jeequan.jeepay.service.impl.TaskListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.List;
/**
* 任务
*/
@RestController
@RequestMapping("/api/taskList")
public class TaskListController extends CommonCtrl {
@Autowired
private TaskListService taskListService;
@Autowired
private MchInfoService mchInfoService;
/**
* 新增任务
* @return
*/
@RequestMapping(value = "/add" ,method = RequestMethod.POST)
public ApiRes addTaskList(){
TaskList taskList = getObject(TaskList.class);
//当前服务商
taskList.setAgentNo(getCurrentAgentNo());
// 当前登录用户信息
SysUser sysUser = getCurrentUser().getSysUser();
taskList.setId(DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6));
taskList.setCreatedBy(String.valueOf(sysUser.getSysUserId()));
boolean save = taskListService.save(taskList);
if (save){
return ApiRes.ok();
}else {
return ApiRes.customFail("新增失败!");
}
}
/**
* 查询
* @return
*/
@RequestMapping(value = "/getPageList" ,method = RequestMethod.GET)
public ApiRes getlistTaskList(){
TaskList taskList = getObject(TaskList.class);
// 时间搜索
Date[] searchDateRange = taskList.buildQueryDateRange();
taskList.setFirstDate(searchDateRange[0]);
taskList.setLastDate(searchDateRange[1]);
taskList.setAgentNo(getCurrentAgentNo());
// 可查看自己和全部下级代理数据
String currentAgentNo = getCurrentAgentNo();
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
// 自己和下级服务商
if (CollUtil.isNotEmpty(subAgentNoList)){
taskList.setSubAgentNoList(subAgentNoList);
}
IPage<TaskList> pageList = taskListService.getPageList(getIPage(), taskList);
//Page<TaskList> page = taskListService.page(getIPage(), TaskList.gw(taskList).orderByDesc(TaskList::getCreatedAt));
return ApiRes.page(pageList);
}
/**
* 查询详情
* @return
*/
@RequestMapping(value = "/{id}" ,method = RequestMethod.GET)
public ApiRes getByIdTaskList(@PathVariable("id") Integer id){
TaskList byId = taskListService.getById(id);
return ApiRes.ok(byId);
}
/**
* 修改
* @return
*/
@RequestMapping(value = "/{id}" ,method = RequestMethod.PUT)
public ApiRes updateTaskList(@PathVariable("id") String id){
TaskList taskList = getObject(TaskList.class);
//当前服务商
taskList.setAgentNo(getCurrentAgentNo());
taskList.setId(id);
boolean resut = taskListService.updateById(taskList);
if (resut){
return ApiRes.ok();
}else {
return ApiRes.customFail("修改失败!");
}
}
/**
* 删除
* @return
*/
@RequestMapping(value = "/{id}" ,method = RequestMethod.DELETE)
public ApiRes deleteTaskList(@PathVariable("id") Integer id){
boolean resut = taskListService.removeById(id);
if (resut){
return ApiRes.ok();
}else {
return ApiRes.customFail("删除失败!");
}
}
}

View File

@@ -0,0 +1,121 @@
package com.jeequan.jeepay.agent.ctrl.aqf;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.converter.TransferConverter;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.SysUser;
import com.jeequan.jeepay.core.interfaces.paychannel.ITransferService;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.service.ValidatorService;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.core.validate.Add;
import com.jeequan.jeepay.db.entity.SysConfig;
import com.jeequan.jeepay.db.entity.TransferInterfaceConfigEntity;
import com.jeequan.jeepay.db.entity.TransferSubjectEntity;
import com.jeequan.jeepay.db.entity.TransferWalletEntity;
import com.jeequan.jeepay.service.impl.TransferInterfaceConfigService;
import com.jeequan.jeepay.service.impl.TransferSubjectService;
import com.jeequan.jeepay.service.impl.TransferWalletService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.UUID;
/**
* 代付对象
*
* @author deng
* @since 2024/5/9
*/
@Slf4j
@RestController
@RequestMapping("/api/transferSubject")
public class TransferSubjectController extends CommonCtrl {
@Autowired
private TransferInterfaceConfigService transferInterfaceConfigService;
@Autowired
private ValidatorService validate;
@Autowired
private TransferSubjectService transferSubjectService;
@Autowired
private TransferWalletService transferWalletService;
@Autowired
private TransferConverter transferConverter;
/**
* 新增转账发起方
*/
@PostMapping("/sponsor")
public ApiRes sponsor() {
TransferSubjectEntity transferSubject = getObject(TransferSubjectEntity.class);
validate.validate(transferSubject, Add.class);
// 当前登录用户信息
transferSubject.setId("SUB" + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6));
SysUser sysUser = getCurrentUser().getSysUser();
transferSubject.setSubjectType("FQ");
transferSubject.setTransApplyId(UUID.randomUUID().toString().replace("-", "").substring(0, 32));
//如果不传递取默认值
if (StringUtils.isEmpty(transferSubject.getIsvNo())) {
SysConfig serviceOne = sysConfigService.getOne(SysConfig.gw().eq(SysConfig::getGroupKey, "defaultConfig")
.eq(SysConfig::getConfigKey, "defaultIsvNo"));
if (serviceOne != null) {
transferSubject.setIsvNo(serviceOne.getConfigVal());
}
}
if (StringUtils.isNotEmpty(transferSubject.getIsvNo())) {
//取对应参数信息
//获取下发金额
TransferInterfaceConfigEntity configEntity = transferInterfaceConfigService.getTransferConfig(transferSubject.getTransIfCode(), transferSubject.getIsvNo(), CS.SYS_ROLE_TYPE.ISV);
if (configEntity != null && StringUtils.isNotEmpty(configEntity.getTransIfParams())) {
String zfbDayMax = JSONObject.parseObject(configEntity.getTransIfParams()).getString("zfbDayMax");
String bankCardDayMax = JSONObject.parseObject(configEntity.getTransIfParams()).getString("bankCardDayMax");
transferSubject.setZfbDayMax(Long.valueOf(zfbDayMax));
transferSubject.setBankCardDayMax(Long.valueOf(bankCardDayMax));
}
}
transferSubject.setCreatedUid(sysUser.getSysUserId());
boolean save = transferSubjectService.save(transferSubject);
if (save) {
return ApiRes.ok();
} else {
return ApiRes.customFail("新增失败!");
}
}
@PostMapping("/refreshBalance")
public ApiRes refreshBalance() {
String transferSubjectId = getValStringRequired("transferSubjectId");
TransferWalletEntity transferWallet = transferWalletService.getByApplyId(transferSubjectId, null);
SpringBeansUtil.getBean(transferWallet.getTransIfCode() + "Transfer");
// 刷新记账本余额
ITransferService transferService = SpringBeansUtil.getBean(transferWallet.getTransIfCode() + "TransferService", ITransferService.class);
MutablePair<String, Long> balanceResult = transferService.queryBalanceAmount(transferConverter.toModel(transferWallet));
// 查询更新余额
transferWallet.setAccountBookBalance(balanceResult.right);
transferWalletService.updateById(transferWallet);
return ApiRes.ok(transferWallet);
}
}

View File

@@ -0,0 +1,66 @@
package com.jeequan.jeepay.agent.ctrl.article;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.SysArticle;
import com.jeequan.jeepay.service.impl.SysArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* 文章管理类
*
* @author yurong
* @date 2022-07-08 14:15
*/
@RestController
@RequestMapping("api/sysArticles")
public class SysArticleController extends CommonCtrl {
@Autowired private SysArticleService sysArticleService;
/**
* @author: yurong
* @date: 2022-07-08 14:15
* @describe: 文章列表 articleType 1公告
*/
@PreAuthorize("hasAuthority('ENT_ARTICLE_NOTICEINFO')")
@RequestMapping(value = "",method = RequestMethod.GET)
public ApiRes articleList(){
SysArticle sysArticle = getObject(SysArticle.class);
if (sysArticle.getArticleType() == null){
return ApiRes.customFail("文章类型不明确");
}
LambdaQueryWrapper<SysArticle> wrapper = SysArticle.gw();
wrapper.select(SysArticle::getArticleId,SysArticle::getTitle,SysArticle::getSubtitle,SysArticle::getPublisher,SysArticle::getCreatedAt)
.eq(SysArticle::getArticleType,sysArticle.getArticleType())
.apply("FIND_IN_SET('"+ CS.SYS_ROLE_TYPE.AGENT+"',"+SysArticle.ARTICLE_RANGE+")")
.orderByDesc(SysArticle::getPublishTime);
IPage<SysArticle> iPage = sysArticleService.page(getIPage(), wrapper);
return ApiRes.page(iPage);
}
/**
* @author: yurong
* @date: 2022-07-08 14:15
* @describe: 文章详情 articleType 1公告
*/
@PreAuthorize("hasAuthority('ENT_ARTICLE_NOTICEINFO')")
@RequestMapping(value = "/{articleId}",method = RequestMethod.GET)
public ApiRes detail(@PathVariable("articleId") Long articleId){
SysArticle sysArticle = sysArticleService.getById(articleId);
if (sysArticle == null) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
return ApiRes.ok(sysArticle);
}
}

View File

@@ -0,0 +1,163 @@
package com.jeequan.jeepay.agent.ctrl.isv;
import com.alibaba.fastjson.JSONArray;
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.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.IsvInfo;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.IsvInfoEntity;
import com.jeequan.jeepay.db.entity.MchConfig;
import com.jeequan.jeepay.service.impl.IsvInfoService;
import com.jeequan.jeepay.service.impl.PayInterfaceConfigService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 服务商管理类
*
* @author pangxiaoyu
* @date 2021-06-07 07:15
*/
@RestController
@RequestMapping("/api/isvInfo")
public class IsvInfoController extends CommonCtrl {
@Autowired
private IsvInfoService isvInfoService;
@Autowired
private PayInterfaceConfigService payInterfaceConfigService;
/**
* @author: pangxiaoyu
* @date: 2021/6/7 16:12
* @describe: 查询服务商信息列表
*/
@PreAuthorize("hasAuthority('ENT_ISV_LIST')")
@RequestMapping(value = "", method = RequestMethod.GET)
public ApiRes list() {
IsvInfoEntity isvInfoEntity = getObject(IsvInfoEntity.class);
LambdaQueryWrapper<IsvInfoEntity> wrapper = IsvInfoEntity.gw();
if (StringUtils.isNotEmpty(isvInfoEntity.getIsvNo())) {
wrapper.eq(IsvInfoEntity::getIsvNo, isvInfoEntity.getIsvNo());
}
if (StringUtils.isNotEmpty(isvInfoEntity.getIsvName())) {
wrapper.eq(IsvInfoEntity::getIsvName, isvInfoEntity.getIsvName());
}
if (isvInfoEntity.getState() != null) {
wrapper.eq(IsvInfoEntity::getState, isvInfoEntity.getState());
}
wrapper.orderByDesc(IsvInfoEntity::getCreatedAt);
IPage<IsvInfoEntity> pages = isvInfoService.page(getIPage(true), wrapper);
return ApiRes.page(pages);
}
/**
* @author: pangxiaoyu
* @date: 2021/6/7 16:13
* @describe: 查看服务商信息
*/
@PreAuthorize("hasAnyAuthority('ENT_ISV_INFO_VIEW', 'ENT_ISV_INFO_EDIT')")
@RequestMapping(value = "/{isvNo}", method = RequestMethod.GET)
public ApiRes detail(@PathVariable("isvNo") String isvNo) {
IsvInfoEntity isvInfoEntity = isvInfoService.getById(isvNo);
if (isvInfoEntity == null) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
return ApiRes.ok(isvInfoEntity);
}
@GetMapping("/isvInfoList")
public ApiRes getIsvInfoList() {
String ifCode = getValStringRequired("ifCode");
String infoType = getValStringRequired("infoType");
String infoId = getValStringRequired("infoId");
String range = getValString("range");
Integer state = getValInteger("state");
String isvName = getValString("isvName");
if ("CURRENTAGENT".equals(infoId)) {
infoId = getCurrentAgentNo();
}
List<IsvInfo> isvAndPayConfig = isvInfoService.getIsvAndPayConfig(infoType, isvName, infoId, ifCode, range, state);
Page<IsvInfo> page = new Page<>();
page.setRecords(isvAndPayConfig);
page.setSize(-1);
page.setPages(1);
if (!CS.SYS_ROLE_TYPE.MCH.equals(infoType)) {
return ApiRes.ok(page);
}
// 如果是查看商户数据,则查询他的默认渠道
List<Map<String, String>> defIsv = mchInfoService.getDefIsv(infoId, ifCode);
if (!ObjectUtils.isEmpty(defIsv)) {
Map<String, String> defIsvItem = defIsv.get(0);
page.getRecords().forEach(r -> {
if (r.getIsvNo().equals(defIsvItem.get(MchConfig.getDefIsvKey(ifCode)))) {
r.addExt("defIsv", CS.YES);
}
});
}
return ApiRes.ok(page);
}
@PostMapping("/autoBindIsvConn")
public ApiRes autoBindIsvConn() {
String isvNo = getValStringRequired("isvNo");
String infoId = getValStringRequired("infoId");
String roleType = getValStringRequired("roleType");
Byte configStatus = getValByteRequired("configStatus");
isvInfoService.autoBindIsvConn(isvNo, infoId, roleType, configStatus);
return ApiRes.ok();
}
@PostMapping("/isvConn")
public ApiRes isvConn() {
String isvNo = getValStringRequired("isvNo");
String infoId = getValStringRequired("infoId");
String infoType = getValStringRequired("infoType");
isvInfoService.saveIsvConn(isvNo, infoType, infoId, getCurrentUser().getSysUser());
return ApiRes.ok();
}
@GetMapping("/getSettType")
public ApiRes getSettType() {
String ifCode = getValStringRequired("ifCode");
String infoId = getValStringRequired("infoId");
JSONArray settType = isvInfoService.getSettType(ifCode, infoId);
return ApiRes.ok(settType);
}
@PostMapping("/editStatus")
public ApiRes editStatus() {
String isvNo = getValStringRequired("isvNo");
String ifCode = getValStringRequired("ifCode");
String infoId = getValStringRequired("infoId");
String infoType = getValStringRequired("infoType");
Integer status = getValIntegerRequired("state");
isvInfoService.editConnStatus(isvNo, ifCode, infoId, infoType, status);
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,38 @@
package com.jeequan.jeepay.agent.ctrl.merchant;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.OCRImgParams;
import com.jeequan.jeepay.service.impl.ImgInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 图片信息OCR
*
* @author xiaoyu
*
* @date 2022/1/12 15:15
*/
@RestController
@RequestMapping("/api/imgInfo")
public class ImgInfoOCRController extends CommonCtrl {
@Autowired private ImgInfoService imgInfoService;
/** 图片信息 **/
@PreAuthorize("hasAuthority('ENT_MCH_IMG_OCR_DETAIL')")
@PostMapping("/detail")
public ApiRes detail() {
String imgUrl = getValStringRequired("imgUrl");
String type = getValStringRequired("type");
// 调用ocr接口
OCRImgParams imgParams = imgInfoService.getImgInfo(imgUrl, type);
return ApiRes.ok(imgParams);
}
}

View File

@@ -0,0 +1,163 @@
package com.jeequan.jeepay.agent.ctrl.merchant;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.DBOEMConfig;
import com.jeequan.jeepay.core.service.ISysConfigService;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.SysUserEntity;
import com.jeequan.jeepay.db.entity.ToDoListModel;
import com.jeequan.jeepay.service.impl.AgentInfoService;
import com.jeequan.jeepay.service.impl.PayOrderService;
import com.jeequan.jeepay.service.impl.StatsTradeService;
import com.jeequan.jeepay.service.impl.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 主页数据类
*
* @author pangxiaoyu
*
* @date 2021-04-27 15:50
*/
@Slf4j
@RestController
@RequestMapping("/api/mainChart")
public class MainChartController extends CommonCtrl {
@Autowired private PayOrderService payOrderService;
@Autowired private SysUserService sysUserService;
@Autowired private AgentInfoService agentInfoService;
@Autowired private ISysConfigService sysConfigService;
@Autowired private StatsTradeService statsTradeService;
/**
* @author: xiaoyu
* @date: 2021/12/28 14:54
* @describe: 今日/昨日交易统计
*/
@PreAuthorize("hasAuthority('ENT_AGENT_MAIN_PAY_DAY_COUNT')")
@RequestMapping(value="/payDayCount", method = RequestMethod.GET)
public ApiRes payDayCount() {
JSONObject reqParamJSON = getReqParamJSON();
List<String> agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
// Map<String, String> agentNoMap = getAgentNo(reqParamJSON);
// JSONObject resJson = payOrderService.payDayCount(null, agentNoMap.get("agentNo"), agentNoMap.get("topAgentNo"), reqParamJSON);
JSONObject resJson = statsTradeService.payDayCount(null, agentSubList, reqParamJSON);
return ApiRes.ok(resJson);
}
/**
* @author: xiaoyu
* @date: 2021/12/28 14:53
* @describe: 趋势图数据
*/
@PreAuthorize("hasAuthority('ENT_AGENT_MAIN_PAY_TREND_COUNT')")
@RequestMapping(value="/payTrendCount", method = RequestMethod.GET)
public ApiRes payTrendCount() {
JSONObject paramJSON = getReqParamJSON();
int recentDay = paramJSON.getIntValue("recentDay");
if (recentDay == 0){
recentDay = 30; // 默认30天
}
paramJSON.put("recentDay", recentDay);
List<String> agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
JSONObject resJson = payOrderService.payTrendCount(paramJSON, null, agentSubList);
return ApiRes.ok(resJson);
}
/**
* @author: xiaoyu
* @date: 2021/12/28 14:54
* @describe: 交易统计
*/
@PreAuthorize("hasAuthority('ENT_AGENT_MAIN_PAY_COUNT')")
@RequestMapping(value="/payCount", method = RequestMethod.GET)
public ApiRes payCount() {
Map<String, String> agentNoMap = getAgentNo(getReqParamJSON());
List<String> agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
// 获取传入参数
JSONObject resJson = payOrderService.mainPagePayCount(null, agentSubList, getReqParamJSON());
return ApiRes.ok(resJson);
}
/**
* @author: xiaoyu
* @date: 2021/12/28 14:54
* @describe: 支付方式统计
*/
@PreAuthorize("hasAuthority('ENT_AGENT_MAIN_PAY_TYPE_COUNT')")
@RequestMapping(value="/payTypeCount", method = RequestMethod.GET)
public ApiRes payWayCount() {
Map<String, String> agentNoMap = getAgentNo(getReqParamJSON());
List<String> agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
ArrayList arrayResult = payOrderService.mainPagePayTypeCount(null, agentSubList, getReqParamJSON());
return ApiRes.ok(arrayResult);
}
/**
* @author: xiaoyu
* @date: 2021/12/28 14:54
* @describe: 服务商基本信息、用户基本信息
*/
@PreAuthorize("hasAuthority('ENT_C_USERINFO')")
@RequestMapping(value="", method = RequestMethod.GET)
public ApiRes userDetail() {
SysUserEntity sysUserEntity = sysUserService.getById(getCurrentUser().getSysUser().getSysUserId());
AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());
Byte infoState = getCurrentUser().getInfoState();
DBOEMConfig dboemConfig = sysConfigService.getOemConfig();
JSONObject json = (JSONObject) JSON.toJSON(agentInfo);
json.put("promiseFile", dboemConfig.getPromiseFile());
json.put("loginUsername", sysUserEntity.getLoginUsername());
json.put("realname", sysUserEntity.getRealname());
json.put("infoState", infoState);
return ApiRes.ok(json);
}
/**
* @author: xiaoyu
* @date: 2022/3/18 16:20
* @describe: 与app共用接口返回服务商号
*/
public Map<String, String> getAgentNo(JSONObject paramJSON) {
HashMap<String, String> AgentNoMap = new HashMap<>();
String agentNo = null;
String topAgentNo = getCurrentAgentNo();
if (StringUtils.isNotEmpty(paramJSON.getString("agentNo"))) {
agentNo = paramJSON.getString("agentNo");
}
AgentNoMap.put("agentNo", agentNo);
AgentNoMap.put("topAgentNo", topAgentNo);
return AgentNoMap;
}
/**
*
* @describe (待办事项)汇总待审核或者待操作的事件数量
*
* @return
*/
@RequestMapping(value = "/getWaitOperationNumber",method = RequestMethod.GET)
public ApiRes getWaitOperationNumber(){
List<ToDoListModel> waitOperationNumber = new ArrayList<>();
return ApiRes.ok(waitOperationNumber);
}
}

View File

@@ -0,0 +1,186 @@
package com.jeequan.jeepay.agent.ctrl.merchant;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.config.SystemYmlConfig;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.components.mq.vender.IMQSender;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.db.entity.MchAppEntity;
import com.jeequan.jeepay.db.entity.MchInfo;
import com.jeequan.jeepay.service.impl.MchAppService;
import com.jeequan.jeepay.service.impl.MchInfoService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 商户应用管理类
*
* @author zhuxiao
*
* @date 2021-06-16 09:15
*/
@RestController
@RequestMapping("/api/mchApps")
public class MchAppController extends CommonCtrl {
@Autowired private MchAppService mchAppService;
@Autowired private MchInfoService mchInfoService;
@Autowired private SystemYmlConfig systemYmlConfig;
@Autowired private IMQSender mqSender;
/**
* @Author: ZhuXiao
* @Description: 应用列表
* @Date: 9:59 2021/6/16
*/
@PreAuthorize("hasAuthority('ENT_MCH_APP_LIST')")
@GetMapping
public ApiRes list() {
MchAppEntity mchAppEntity = getObject(MchAppEntity.class);
mchAppEntity.setAgentNo(getCurrentAgentNo());
// app融合搜索appId appName mchNo mchName
mchAppEntity.addExt("unionSearchId", getValStringDefault("unionSearchId", ""));
// 可查看自己和全部下级代理数据
String currentAgentNo = getCurrentAgentNo();
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
// 自己和下级服务商
if (CollUtil.isNotEmpty(subAgentNoList)){
mchAppEntity.setSubAgentNoList(subAgentNoList);
}
IPage<MchAppEntity> pages = mchAppService.selectPage(getIPage(true), mchAppEntity);
return ApiRes.page(pages);
}
/**
* @Author: ZhuXiao
* @Description: 新建应用
* @Date: 10:05 2021/6/16
*/
@PreAuthorize("hasAuthority('ENT_MCH_APP_ADD')")
@MethodLog(remark = "新建应用")
@PostMapping
public ApiRes add() {
MchAppEntity mchAppEntity = getObject(MchAppEntity.class);
if (StringUtils.isEmpty(mchAppEntity.getMchNo())) {
throw new BizException("商户号不能为空");
}
MchInfo mchInfo = mchInfoService.getById(mchAppEntity.getMchNo());
if (mchInfo == null || !mchInfo.getAgentNo().equals(getCurrentAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
mchAppEntity.setMchNo(mchInfo.getMchNo());
mchAppEntity.setAgentNo(getCurrentAgentNo());
mchAppEntity.setTopAgentNo(mchInfo.getTopAgentNo());
mchAppEntity.setAppId(SeqKit.getMchAppId());
//默认设置为审核中
mchAppEntity.setState(MchAppEntity.AUDIT);
// 如果当前为默认
if (mchAppEntity.getDefaultFlag() == CS.YES) {
mchAppService.update(new LambdaUpdateWrapper<MchAppEntity>()
.set(MchAppEntity::getDefaultFlag, CS.NO)
.eq(MchAppEntity::getMchNo, mchAppEntity.getMchNo())
);
}
boolean result = mchAppService.save(mchAppEntity);
if (!result) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_CREATE);
}
return ApiRes.ok();
}
/**
* @Author: ZhuXiao
* @Description: 应用详情
* @Date: 10:13 2021/6/16
*/
@PreAuthorize("hasAnyAuthority('ENT_MCH_APP_VIEW', 'ENT_MCH_APP_EDIT')")
@GetMapping("/{appId}")
public ApiRes detail(@PathVariable("appId") String appId) {
MchAppEntity mchAppEntity = mchAppService.selectById(appId);
if (mchAppEntity == null || !mchAppEntity.getAgentNo().equals(getCurrentAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
return ApiRes.ok(mchAppEntity);
}
/**
* @Author: ZhuXiao
* @Description: 更新应用信息
* @Date: 10:11 2021/6/16
*/
@PreAuthorize("hasAuthority('ENT_MCH_APP_EDIT')")
@MethodLog(remark = "更新应用信息")
@PutMapping("/{appId}")
public ApiRes update(@PathVariable("appId") String appId) {
MchAppEntity mchAppEntity = getObject(MchAppEntity.class);
mchAppEntity.setAppId(appId);
MchAppEntity dbMchAppEntity = mchAppService.getById(appId);
if (!dbMchAppEntity.getAgentNo().equals(getCurrentAgentNo())) {
throw new BizException("无权操作!");
}
if (mchAppEntity.getDefaultFlag() != null && !dbMchAppEntity.getDefaultFlag().equals(mchAppEntity.getDefaultFlag())) {
// 如果修改当前为默认
if (mchAppEntity.getDefaultFlag() == CS.YES) {
mchAppService.update(new LambdaUpdateWrapper<MchAppEntity>()
.set(MchAppEntity::getDefaultFlag, CS.NO)
.eq(MchAppEntity::getMchNo, dbMchAppEntity.getMchNo())
);
}else {
throw new BizException("应用不可修改为非默认!");
}
}
boolean result = mchAppService.updateById(mchAppEntity);
if (!result) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
}
return ApiRes.ok();
}
/**
* @Author: ZhuXiao
* @Description: 删除应用
* @Date: 10:14 2021/6/16
*/
@PreAuthorize("hasAuthority('ENT_MCH_APP_DEL')")
@MethodLog(remark = "删除应用")
@DeleteMapping("/{appId}")
public ApiRes delete(@PathVariable("appId") String appId) {
MchAppEntity mchAppEntity = mchAppService.getById(appId);
if (!mchAppEntity.getAgentNo().equals(getCurrentAgentNo())) {
throw new BizException("无权操作!");
}
mchAppService.removeByAppId(appId);
return ApiRes.ok();
}
/** 功能描述: 查询系统公钥 */
@PreAuthorize("hasAnyAuthority('ENT_MCH_APP_ADD', 'ENT_MCH_APP_EDIT')")
@GetMapping("/sysRSA2PublicKey")
public ApiRes sysRSA2PublicKey() {
return ApiRes.ok(systemYmlConfig.getSysRSA2PublicKey());
}
}

View File

@@ -0,0 +1,120 @@
package com.jeequan.jeepay.agent.ctrl.merchant;
import cn.hutool.core.util.ObjUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.MchConfig;
import com.jeequan.jeepay.service.impl.MchConfigService;
import com.jeequan.jeepay.service.impl.MchInfoService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 商户配置管理类
*
* @author zx
* @date 2021-06-16 09:15
*/
@RestController
@RequestMapping("/api/mchConfig")
public class MchConfigController extends CommonCtrl {
@Autowired
private MchConfigService mchConfigService;
@Autowired
private MchInfoService mchInfoService;
/**
* @Author: zx
* @Description: 查询商户配置
* @Date: 9:59 2021/6/16
*/
@PreAuthorize("hasAuthority('ENT_MCH_CONFIG_PAGE')")
@GetMapping
public ApiRes list() {
String groupKey = getValString("groupKey");
String mchNo = getValStringRequired("mchNo");
String mchAppId = getValString("mchAppId");
String mchApplyId = getValString("mchApplyId");
LambdaQueryWrapper<MchConfig> queryWrapper = MchConfig.gw()
.eq(MchConfig::getMchNo, mchNo)
.eq(!ObjUtil.isEmpty(mchAppId), MchConfig::getMchAppId, mchAppId)
.eq(!ObjUtil.isEmpty(mchApplyId), MchConfig::getMchApplyId, mchApplyId);
if (StringUtils.isNotBlank(groupKey)) {
queryWrapper.eq(MchConfig::getGroupKey, groupKey);
}
List<MchConfig> list = mchConfigService.list(queryWrapper);
return ApiRes.ok(list);
}
/**
* @Author: zx
* @Description: 根据configKey查询商户配置
* @Date: 9:59 2021/6/16
*/
@PreAuthorize("hasAuthority('ENT_MCH_CONFIG_EDIT')")
@GetMapping("/{configKey}")
public ApiRes get(@PathVariable("configKey") String configKey) {
MchConfig mchConfig = mchConfigService.getOne(MchConfig.gw().eq(MchConfig::getMchNo, getValStringRequired("mchNo")).eq(MchConfig::getConfigKey, configKey));
return ApiRes.ok(mchConfig);
}
/**
* @Author: zx
* @Description: 根据configKey更新商户配置信息
* @Date: 10:11 2021/6/16
*/
/*@PreAuthorize("hasAuthority('ENT_MCH_CONFIG_EDIT')")
@MethodLog(remark = "更新商户配置")
@PutMapping("/{configKey}")
public ApiRes updateByConfigKey(@PathVariable("configKey") String configKey) {
MchConfig mchConfig = getObject(MchConfig.class);
mchConfig.setConfigKey(configKey);
int count = mchConfigService.saveOrUpdateConfig(mchConfig, getCurrentMchNo());
if(count <= 0) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
}
return ApiRes.ok();
}*/
/**
* @author: zx
* @Description: 批量更新商户配置信息
* @Date: 10:11 2021/6/16
*/
@PreAuthorize("hasAuthority('ENT_MCH_CONFIG_PAGE')")
@MethodLog(remark = "批量更新商户配置信息")
@PutMapping("/{groupKey}")
public ApiRes updateBatch(@PathVariable("groupKey") String groupKey) {
String params = getValStringRequired("configData");
List<MchConfig> mchConfigList = JSONArray.parseArray(params, MchConfig.class);
String mchNo = getValStringRequired("mchNo");
String mchAppId = getValString("mchAppId");
String mchApplyId = getValString("mchApplyId");
int update = mchConfigService.updateBatch(mchConfigList, mchNo, mchAppId, mchApplyId, groupKey);
if (update <= 0) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
}
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,221 @@
package com.jeequan.jeepay.agent.ctrl.merchant;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.DesensitizedUtil;
import com.alibaba.fastjson.JSONArray;
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.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager;
import com.jeequan.jeepay.components.mq.model.CleanMchLoginAuthCacheMQ;
import com.jeequan.jeepay.components.mq.model.ResetIsvMchAppInfoConfigMQ;
import com.jeequan.jeepay.components.mq.vender.IMQSender;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.SysUser;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.PrefixConfig;
import com.jeequan.jeepay.core.model.smsconfig.SmsBizDiyContentModel;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.MchInfo;
import com.jeequan.jeepay.service.impl.MchInfoService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* 商户管理类
*
* @author pangxiaoyu
* @site https://www.jeequan.com
* @date 2021-06-07 07:15
*/
@RestController
@RequestMapping("/api/mchInfo")
public class MchInfoController extends CommonCtrl {
@Autowired private IMQSender mqSender;
@Autowired private SmsManager smsManager;
@Autowired private PrefixConfig prefixConfig;
@Autowired private MchInfoService mchInfoService;
/**
* @author: pangxiaoyu
* @date: 2021/6/7 16:14
* @describe: 商户信息列表
*/
@PreAuthorize("hasAuthority('ENT_MCH_LIST')")
@GetMapping(value = "")
public ApiRes list() {
MchInfo mchInfo = getObject(MchInfo.class);
// 仅查询当前服务商数据
mchInfo.setAgentNo(getCurrentAgentNo());
// 扩展员仅查询自己的数据
if (getCurrentUser().isEpUser()){
mchInfo.setCreatedUid(getCurrentUser().getSysUser().getSysUserId());
}
Page<MchInfo> listPage = mchInfoService.getListPage(getIPage(), mchInfo);
return ApiRes.page(listPage);
}
/**
* @author: pangxiaoyu
* @date: 2021/6/7 16:14
* @describe: 新增商户信息
*/
@PreAuthorize("hasAuthority('ENT_MCH_INFO_ADD')")
@MethodLog(remark = "新增商户")
@PostMapping
public ApiRes add() {
AgentInfo pAgentInfo = agentInfoService.getById(getCurrentAgentNo());
// 当前服务商是否允许发展下级商户
if (pAgentInfo.getAddMchFlag() != CS.YES) {
throw new BizException("当前服务商不可发展下级商户");
}
MchInfo mchInfo = getObject(MchInfo.class);
// 获取传入的商户登录名、登录密码
String loginPassword = getValString("loginPassword");
Byte isNotify = getValByteRequired("isNotify");
if (StringUtils.isBlank(loginPassword)) {
loginPassword = null;
}
mchInfo.setMchNo(SeqKit.genMchNo());
// 当前服务商
mchInfo.setAgentNo(getCurrentAgentNo());
mchInfo.setTopAgentNo(agentInfoService.queryTopAgentNo(getCurrentAgentNo()));
// 商户类型
mchInfo.setType(MchInfo.TYPE_ISVSUB);
// 商户级别
mchInfo.setMchLevel(MchInfo.MCH_LEVEL_M0);
// 商户退款权限
JSONArray refundModeArray = new JSONArray();
refundModeArray.add(MchInfo.REFUND_MODEL_PLAT);
refundModeArray.add(MchInfo.REFUND_MODEL_API);
mchInfo.setRefundMode(refundModeArray);
// 当前登录用户信息
SysUser sysUser = getCurrentUser().getSysUser();
mchInfo.setCreatedUid(sysUser.getSysUserId());
mchInfo.setCreatedBy(sysUser.getRealname());
mchInfoService.addMch(mchInfo, loginPassword);
// 发送短信通知
if (isNotify == CS.YES) {
smsManager.sendDiyContentSms(SmsBizDiyContentModel.genUserOpenAccount(mchInfo.getContactTel(), mchInfo.getLoginUsername(), loginPassword));
}
return ApiRes.ok();
}
/**
* @author: pangxiaoyu
* @date: 2021/6/7 16:14
* @describe: 删除商户信息
*/
@PreAuthorize("hasAuthority('ENT_MCH_INFO_DEL')")
@MethodLog(remark = "删除商户")
@RequestMapping(value="/{mchNo}", method = RequestMethod.DELETE)
public ApiRes delete(@PathVariable("mchNo") String mchNo) {
MchInfo mchInfo = mchInfoService.getById(mchNo);
if (mchInfo == null) {
throw new BizException("该商户不存在");
}
if (!mchInfo.getAgentNo().equals(getCurrentAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
List<Long> userIdList = mchInfoService.removeByMchNo(mchNo);
// 推送mq删除redis用户缓存
mqSender.send(CleanMchLoginAuthCacheMQ.build(userIdList));
// 推送mq到目前节点进行更新数据
mqSender.send(ResetIsvMchAppInfoConfigMQ.build(ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_INFO, null, mchNo, null));
return ApiRes.ok();
}
/**
* @author: pangxiaoyu
* @date: 2021/6/7 16:14
* @describe: 更新商户信息
*/
@PreAuthorize("hasAuthority('ENT_MCH_INFO_EDIT')")
@MethodLog(remark = "更新商户信息")
@RequestMapping(value="/{mchNo}", method = RequestMethod.PUT)
public ApiRes update(@PathVariable("mchNo") String mchNo) {
//获取查询条件
MchInfo mchInfo = getObject(MchInfo.class);
mchInfo.setMchNo(mchNo); //设置商户号主键
mchInfo.setType(null); //防止变更商户类型
mchInfo.setAgentNo(null);
// mchInfo.setIsvNo(null); // 防止变更服务商ID
mchInfo.setTopAgentNo(null); // 防止变更顶级代理ID
mchInfo.setRefundMode(null); // 防止变更退款权限
mchInfo.setLoginUsername(null); // 防止修改用户登录名
MchInfo dbRecord = mchInfoService.getById(mchNo);
if (dbRecord == null || !getCurrentAgentNo().equals(dbRecord.getAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
// 状态禁止操作:平台停用 -> 启用
if (mchInfo.getState() != null && mchInfo.getState() == CS.YES && dbRecord.getState() == MchInfo.STATE_NO_MGR) {
throw new BizException("商户状态停用,请联系运营平台处理");
}
// 数据库状态为 由平台停用的,不可修改
if (dbRecord.getState() == MchInfo.STATE_NO_MGR) {
mchInfo.setState(null);
}
boolean resetPass = getReqParamJSON().getBooleanValue("resetPass");
String confirmPwd = null;
if(resetPass){
confirmPwd = getReqParamJSON().getBoolean("defaultPass") ? null : Base64.decodeStr(getValStringRequired("confirmPwd"));
}
// 更新商户 & 得到需要删除的商户用户ID的记录
Set<Long> removeCacheUserIdList = mchInfoService.updateMch(mchInfo, resetPass, confirmPwd);
// 推送mq删除redis用户认证信息
if (!removeCacheUserIdList.isEmpty()) {
mqSender.send(CleanMchLoginAuthCacheMQ.build(new ArrayList<>(removeCacheUserIdList)));
}
// 推送mq到目前节点进行更新数据
mqSender.send(ResetIsvMchAppInfoConfigMQ.build(ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_INFO, null, mchNo, null));
return ApiRes.ok();
}
/**
* @author: pangxiaoyu
* @date: 2021/6/7 16:14
* @describe: 查询商户信息
*/
@PreAuthorize("hasAnyAuthority('ENT_MCH_INFO_VIEW', 'ENT_MCH_INFO_EDIT')")
@RequestMapping(value="/{mchNo}", method = RequestMethod.GET)
public ApiRes detail(@PathVariable("mchNo") String mchNo) {
MchInfo mchInfo = mchInfoService.getById(mchNo);
if (mchInfo == null) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
if (mchInfo.getState() == MchInfo.STATE_NO_MGR) {
mchInfo.setState(CS.NO);
}
return ApiRes.ok(mchInfo);
}
}

View File

@@ -0,0 +1,71 @@
package com.jeequan.jeepay.agent.ctrl.merchant;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.MchInfo;
import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity;
import com.jeequan.jeepay.service.impl.MchModifyApplymentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
/**
* TODO
*
* @author crystal
* @date 2023/12/27 15:36
*/
@RestController
@RequestMapping("/api/mchModifyApplyment")
public class MchModifyApplymentController extends CommonCtrl {
@Autowired private MchModifyApplymentService modifyApplymentService;
@GetMapping
public ApiRes list() {
MchModifyApplymentEntity modifyApplyment = getObject(MchModifyApplymentEntity.class);
JSONObject paramJSON = getReqParamJSON();
//查询该服务商下的所有用户数据(包括自己和下级服务商)
String currentAgentNo = getCurrentAgentNo();
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
List<String> mchInfoList = mchInfoService.list(MchInfo.gw()
.in(MchInfo::getAgentNo, subAgentNoList)
.eq(MchInfo::getState,1))
.stream()
.map(MchInfo::getMchNo).collect(Collectors.toList());
modifyApplyment.setMchInfoList(mchInfoList);
Page<MchModifyApplymentEntity> pages = modifyApplymentService.pageList(getIPage(), modifyApplyment,paramJSON);
return ApiRes.page(pages);
}
@GetMapping("/result/{modifyApplyId}")
public ApiRes getResult(@PathVariable("modifyApplyId") String modifyApplyId) {
modifyApplymentService.getResult(modifyApplyId);
return ApiRes.ok();
}
@PreAuthorize("hasAuthority('ENT_MCH_APPLYMENT_VIEW')")
@GetMapping("/{recordId}")
public ApiRes detail(@PathVariable("recordId") String recordId) {
Byte originData = getValByteDefault("originData", CS.NO);
MchModifyApplymentEntity record;
if (CS.NO == originData) {
record = modifyApplymentService.getInfoById(recordId);
} else {
record = modifyApplymentService.getById(recordId);
}
return ApiRes.ok(record);
}
}

View File

@@ -0,0 +1,89 @@
package com.jeequan.jeepay.agent.ctrl.merchant;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.components.mq.vender.IMQSender;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.DBApplicationConfig;
import com.jeequan.jeepay.db.entity.MchAppEntity;
import com.jeequan.jeepay.db.entity.PayInterfaceConfig;
import com.jeequan.jeepay.service.impl.MchAppService;
import com.jeequan.jeepay.service.impl.MchInfoService;
import com.jeequan.jeepay.service.impl.PayInterfaceConfigService;
import com.jeequan.jeepay.service.impl.SysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.HashSet;
import java.util.Set;
/**
* 商户支付接口配置类
*
* @author zhuxiao
*
* @date 2021-04-27 15:50
*/
@RestController
@RequestMapping("/api/mch/payConfigs")
public class MchPayInterfaceConfigController extends CommonCtrl {
@Autowired
private PayInterfaceConfigService payInterfaceConfigService;
@Autowired
private MchInfoService mchInfoService;
@Autowired
private MchAppService mchAppService;
@Autowired
private SysConfigService sysConfigService;
@Autowired
private IMQSender mqSender;
/**
* 查询支付宝商户授权URL
**/
@GetMapping("/alipayIsvsubMchAuthUrls/{mchAppId}/{isvNo}")
public ApiRes queryAlipayIsvsubMchAuthUrl(@PathVariable("mchAppId") String mchAppId,
@PathVariable("isvNo") String isvNo) {
MchAppEntity mchAppEntity = mchAppService.getById(mchAppId);
DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig();
String authUrl = dbApplicationConfig.genAlipayIsvsubMchAuthUrl(isvNo, mchAppId);
String authQrImgUrl = dbApplicationConfig.genScanImgUrl(authUrl);
JSONObject result = new JSONObject();
result.put("authUrl", authUrl);
result.put("authQrImgUrl", authQrImgUrl);
return ApiRes.ok(result);
}
/**
* 查询当前应用支持的支付接口
*/
@PreAuthorize("hasAuthority( 'ENT_DIVISION_RECEIVER_ADD' )")
@RequestMapping(value = "ifCodes/{appId}", method = RequestMethod.GET)
public ApiRes getIfCodeByAppId(@PathVariable("appId") String appId) {
if (mchAppService.lambdaQuery().eq(MchAppEntity::getMchNo, getCurrentAgentNo()).eq(MchAppEntity::getAppId, appId).count() <= 0) {
throw new BizException("商户应用不存在");
}
Set<String> result = new HashSet<>();
payInterfaceConfigService.lambdaQuery().select(PayInterfaceConfig::getIfCode)
.eq(PayInterfaceConfig::getState, CS.PUB_USABLE)
.eq(PayInterfaceConfig::getInfoId, appId)
.eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.MCH_APP)
.list().forEach(r -> result.add(r.getIfCode()));
return ApiRes.ok(result);
}
}

View File

@@ -0,0 +1,77 @@
package com.jeequan.jeepay.agent.ctrl.merchant;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.core.ctrls.AbstractCtrl;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.MchVideoCacheEntity;
import com.jeequan.jeepay.service.impl.MchVideoCacheService;
import com.jeequan.jeepay.thirdparty.service.wxchannel.WechatChannelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/mchVideo")
public class MchVideoController extends AbstractCtrl {
@Autowired
private WechatChannelService wechatChannelService;
@Autowired
private MchVideoCacheService mchVideoCacheService;
@PostMapping("/authTask")
public ApiRes auth() {
String mchNo = getValStringRequired("mchNo");
JSONObject task = wechatChannelService.createTask(mchNo);
return ApiRes.ok(task);
}
@GetMapping("/authTask")
public ApiRes taskResult() {
String taskId = getValStringRequired("taskId");
JSONObject taskResult = wechatChannelService.queryTask(taskId);
return ApiRes.ok(taskResult);
}
@GetMapping("/dataList")
public ApiRes cacheList() {
Page<MchVideoCacheEntity> iPage = getIPage();
MchVideoCacheEntity mchInfo = getObject(MchVideoCacheEntity.class);
LambdaQueryWrapper<MchVideoCacheEntity> wrapper = Wrappers.lambdaQuery(mchInfo);
Page<MchVideoCacheEntity> page = mchVideoCacheService.page(iPage, wrapper);
return ApiRes.ok(page);
}
@GetMapping("/randomOne")
public ApiRes randomOne() {
String mchNo = getValStringRequired("mchNo");
MchVideoCacheEntity result = mchVideoCacheService.getRandomOne(mchNo);
return ApiRes.ok(result);
}
@DeleteMapping("/{id}")
public ApiRes remove(@PathVariable("id") Long id) {
mchVideoCacheService.removeById(id);
return ApiRes.ok();
}
@PostMapping("/choiceFlag/{id}")
public ApiRes choiceFlag(@PathVariable("id") Long id) {
String choiceFlag = getValStringRequired("choiceFlag");
mchVideoCacheService.lambdaUpdate()
.eq(MchVideoCacheEntity::getId, id)
.set(MchVideoCacheEntity::getChoiceFlag, choiceFlag)
.update();
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,100 @@
package com.jeequan.jeepay.agent.ctrl.merchant;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.MchInfo;
import com.jeequan.jeepay.db.entity.PackageInfo;
import com.jeequan.jeepay.db.entity.PackageOrder;
import com.jeequan.jeepay.service.impl.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/packageInfo")
public class PackageInfoController extends CommonCtrl {
@Autowired private PackageInfoService packageInfoService;
@Autowired private PackageProductService packageProductService;
@Autowired private ProductInfoService productInfoService;
@Autowired private ProductAppService productAppService;
@Autowired private PackageTypeService packageTypeService;
@RequestMapping(value = "/getPackageList", method = RequestMethod.GET)
@MethodLog(remark = "方案中心列表")
public ApiRes getPackageList() throws BizException {
PackageInfo packageInfo = getObject(PackageInfo.class);
Page<PackageInfo> page = new Page<>();
List<PackageInfo> packageInfoList = packageInfoService.getPackageList(packageInfo.getName(),packageInfo.getState(),packageInfo.getPackageType());
page.setRecords(packageInfoList);
page.setTotal(packageInfoList.size());
page.setCurrent(1);
return ApiRes.ok(page);
}
@RequestMapping(value = "/getPackageById", method = RequestMethod.GET)
@MethodLog(remark = "商户端方案详情")
public ApiRes getPackageById() throws BizException {
//获取查询条件
PackageInfo packageInfo = getObject(PackageInfo.class);
PackageInfo info = packageInfoService.getPackageById(packageInfo.getPackageId());
return ApiRes.ok(info);
}
@GetMapping("/getPackageOder")
@MethodLog(remark = "开通记录")
public ApiRes getPackageOder(){
Page<PackageOrder> page=getIPage(true);
PackageOrder packageOrder = getObject(PackageOrder.class);
// 时间搜索
Date[] searchDateRange = packageOrder.buildQueryDateRange();
packageOrder.setFirstDate(searchDateRange[0]);
packageOrder.setLastDate(searchDateRange[1]);
//packageOrder.setCreatedUid(getCurrentUser().getSysUserId());
//查询该服务商下的所有用户数据(包括自己和下级服务商)
String currentAgentNo = getCurrentAgentNo();
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
List<String> mchInfoList = mchInfoService.list(MchInfo.gw()
.in(MchInfo::getAgentNo, subAgentNoList)
.eq(MchInfo::getState,1))
.stream()
.map(MchInfo::getMchNo).collect(Collectors.toList());
packageOrder.setMchInfoList(mchInfoList);
Page<PackageOrder> result = productAppService.getProductAppList(page, packageOrder);
return ApiRes.ok(result);
}
@RequestMapping(value = "/getPackageOderById", method = RequestMethod.GET)
@MethodLog(remark = "开通记录详情")
public ApiRes getPackageOderById() throws BizException {
//获取查询条件
PackageOrder packageOrder = getObject(PackageOrder.class);
PackageOrder serviceById = productAppService.getDetail(packageOrder.getId());
return ApiRes.ok(serviceById);
}
@MethodLog(remark = "更新开通记录")
@RequestMapping(value="/{id}", method = RequestMethod.PUT)
public ApiRes update(@PathVariable("id") String id) {
PackageOrder packageOrder = getObject(PackageOrder.class);
packageOrder.setId(id);//设置主键
packageOrder.setUpdatedAt(new Date());
packageOrder.setState(1);
productAppService.updateById(packageOrder);
return ApiRes.ok();
}
@RequestMapping(value = "/getPackageTypeList", method = RequestMethod.GET)
@MethodLog(remark = "获取所有方案分类列表")
public ApiRes getPackageTypeList() throws BizException {
return ApiRes.ok(packageTypeService.list());
}
}

View File

@@ -0,0 +1,140 @@
package com.jeequan.jeepay.agent.ctrl.merchant;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.bizcommons.manage.MchStoreTerminalManage;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.MchStoreTerminal;
import com.jeequan.jeepay.service.impl.MchStoreTerminalService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/***
* 终端设备管理
*
* @author terrfly
*
* @date 2022/4/26 17:34
*/
@Slf4j
@RestController
@RequestMapping("/api/mchTerminals")
public class TerminalController extends CommonCtrl {
@Autowired private MchStoreTerminalService mchStoreTerminalService;
@Autowired private MchStoreTerminalManage mchStoreTerminalManage;
@PreAuthorize("hasAuthority('ENT_TERMINAL_LIST')")
@GetMapping
public ApiRes pages() {
// 请求参数
MchStoreTerminal queryObject = getObject(MchStoreTerminal.class);
// 可查看自己和全部下级代理的设备
String currentAgentNo = getCurrentAgentNo();
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
// 自己和下级服务商
if (CollUtil.isNotEmpty(subAgentNoList)){
queryObject.setSubAgentNoList(subAgentNoList);
}
IPage<MchStoreTerminal> page = mchStoreTerminalService.getMchStoreTerminalList(getIPage(), queryObject);
return ApiRes.page(page);
}
/** detail */
@PreAuthorize("hasAuthority( 'ENT_TERMINAL_VIEW' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.GET)
public ApiRes detail(@PathVariable("recordId") String recordId) {
return ApiRes.ok(mchStoreTerminalService.getById(recordId));
}
/** add */
@PreAuthorize("hasAuthority( 'ENT_TERMINAL_ADD' )")
@MethodLog(remark = "添加商户终端信息")
@RequestMapping(value="", method = RequestMethod.POST)
public ApiRes add() {
return mchStoreTerminalManage.add(getObject(MchStoreTerminal.class));
}
/** update */
@PreAuthorize("hasAuthority( 'ENT_TERMINAL_EDIT' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.PUT)
@MethodLog(remark = "更新商户终端信息")
public ApiRes update(@PathVariable("recordId") Long recordId) {
MchStoreTerminal record = getObject(MchStoreTerminal.class);
record.setTrmId(recordId);
return mchStoreTerminalManage.update(record);
}
/** update */
@PreAuthorize("hasAuthority( 'ENT_TERMINAL_EDIT' )")
@RequestMapping(value="/trmDefaults", method = RequestMethod.PUT)
@MethodLog(remark = "更新商户终端默认状态")
public ApiRes updateDefault() {
return mchStoreTerminalManage.updateDefault(getValLongRequired("trmId"), getValByteRequired("defaultFlag"));
}
/** delete */
@PreAuthorize("hasAuthority('ENT_TERMINAL_DEL')")
@MethodLog(remark = "删除终端")
@RequestMapping(value="/{recordId}", method = RequestMethod.DELETE)
public ApiRes del(@PathVariable("recordId") String recordId) {
mchStoreTerminalService.removeById(recordId);
return ApiRes.ok();
}
/** 报备列表 */
@PreAuthorize("hasAuthority('ENT_TERMINAL_SENDUP')")
@RequestMapping(value="channelBindInfos/{recordId}", method = RequestMethod.GET)
public ApiRes channelBindInfos(@PathVariable("recordId") Long recordId) {
return mchStoreTerminalManage.getChannelBindInfos(recordId);
}
/** 终端报备 */
@PreAuthorize("hasAuthority('ENT_TERMINAL_SENDUP')")
@MethodLog(remark = "终端报备")
@RequestMapping(value="channelSendup/{recordId}", method = RequestMethod.POST)
public ApiRes channelSendup(@PathVariable("recordId") Long recordId) {
String ifCode = getValStringRequired("ifCode");
Byte state = getValByteRequired("state"); // 0 - 取消报备, 1- 申请报备
return mchStoreTerminalManage.channelSendup(recordId, ifCode, state);
}
/** 修改终端报备信息 */
@PreAuthorize("hasAuthority('ENT_TERMINAL_SENDUP')")
@MethodLog(remark = "自定义终端报备信息")
@RequestMapping(value="channelBindInfos/{recordId}", method = RequestMethod.POST)
public ApiRes updChannelBindInfos(@PathVariable("recordId") Long recordId) {
String ifCode = getValStringRequired("ifCode");
String channelTrmNo = getValStringDefault("channelTrmNo", ""); // 报备信息
Byte state = getValByteRequired("state");
return mchStoreTerminalManage.updChannelBindInfos(recordId, ifCode, channelTrmNo, state);
}
}

View File

@@ -0,0 +1,171 @@
package com.jeequan.jeepay.agent.ctrl.merchant;
import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.zxing.WriterException;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.agent.util.CodeImgUtil;
import com.jeequan.jeepay.components.oss.config.OssYmlConfig;
import com.jeequan.jeepay.components.oss.model.OssFileConfig;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.DBApplicationConfig;
import com.jeequan.jeepay.core.model.DBOSSConfig;
import com.jeequan.jeepay.core.model.DBWxMpConfig;
import com.jeequan.jeepay.db.entity.MchInfo;
import com.jeequan.jeepay.db.entity.MchWxmpUser;
import com.jeequan.jeepay.service.impl.MchInfoService;
import com.jeequan.jeepay.service.impl.MchWxmpUserService;
import com.jeequan.jeepay.service.impl.SysConfigService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.io.File;
import java.io.IOException;
/**
* 微信公众号提醒配置类
*
* @author zx
*
* @date 2021-10-15 09:15
*/
@RestController
@RequestMapping("/api/wxmp")
public class WxMpUserController extends CommonCtrl {
@Autowired private MchInfoService mchInfoService;
@Autowired private SysConfigService sysConfigService;
@Autowired private MchWxmpUserService mchWxmpUserService;
@Autowired private OssYmlConfig ossYmlConfig;
/**
* @Author: zx
* @Description: 商户创建微信公众号接收者的显示信息
* @Date: 2021-10-15 09:15
*/
@GetMapping("/getWxmpInfo")
public ApiRes getWxmpInfo() {
MchInfo mchInfo = mchInfoService.getById(getCurrentUser().getSysUser().getBelongInfoId());
DBApplicationConfig applicationConfig = sysConfigService.getDBApplicationConfig();
DBOSSConfig ossConfig = sysConfigService.getOssConfig();
DBWxMpConfig wxMpConfig = sysConfigService.getDBWxMpConfig();
if(wxMpConfig == null){
throw new BizException("未正确配置微信公众号消息配置项");
}
String mchAuthRedirectUrl = StringUtils.isBlank(wxMpConfig.getMchAuthRedirectUrl()) ? DBWxMpConfig.DEFAULT_WX_AUTH_DOMAIN : wxMpConfig.getMchAuthRedirectUrl();
JSONObject result = new JSONObject();
String authUrl = DBWxMpConfig.mchAuthUrl
.replace("{{mchAuthRedirectUrl}}", mchAuthRedirectUrl)
.replace("{{mchNo}}", mchInfo.getMchNo())
.replace("{{appId}}", wxMpConfig.getWxAppId())
.replace("{{paySiteUrl}}", applicationConfig.getPaySiteUrl());
// 文件地址 (xxx/xxx.jpg 格式)
String filePath = ossYmlConfig.getOss().getFilePublicPath() + File.separator + OssFileConfig.BIZ_TYPE.WX_FILE + File.separator;
String fileName = UUID.fastUUID() + ".png";
try {
CodeImgUtil.codeImgEncode(filePath, fileName, authUrl, 200, 200);
result.put("authQr", ossConfig.getOssPublicSiteUrl() + File.separator + OssFileConfig.BIZ_TYPE.WX_FILE + File.separator + fileName);
result.put("wxmpQr", wxMpConfig.getWxmpUrl());
return ApiRes.ok(result);
} catch (WriterException | IOException e) {
logger.error("", e);
return ApiRes.customFail("获取授权码失败");
}
}
/**
* @Author: zx
* @Description: 微信公众号取消关注
* @Date: 2021-10-15 09:15
*/
@GetMapping("/unAuth")
public ApiRes unAuth() {
LambdaUpdateWrapper<MchWxmpUser> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(MchWxmpUser::getMchNo, getCurrentAgentNo());
updateWrapper.set(MchWxmpUser::getSendStatus, MchWxmpUser.SEND_STATE_CLOSE);
boolean updateResult = mchWxmpUserService.update(updateWrapper);
if (!updateResult) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
}
return ApiRes.ok();
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 微信公众号消息接收者列表
*/
@PreAuthorize("hasAuthority('ENT_MCH_WXMP_USER_LIST')")
@GetMapping
public ApiRes pages() {
LambdaQueryWrapper<MchWxmpUser> gw = MchWxmpUser.gw();
gw.eq(MchWxmpUser::getMchNo, getCurrentAgentNo());
if (StringUtils.isNotBlank(getValString("nickname"))) {
gw.like(MchWxmpUser::getNickname, getValString("nickname"));
}
IPage<MchWxmpUser> page = mchWxmpUserService.page(getIPage(), gw);
//返回数据
return ApiRes.page(page);
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 微信公众号消息接收者修改
*/
@PreAuthorize("hasAuthority('ENT_MCH_WXMP_USER_EDIT')")
@MethodLog(remark = "微信公众号消息接收者修改")
@PutMapping("/{userId}")
public ApiRes update(@PathVariable("userId") Long userId) {
MchWxmpUser mchWxmpUser = getObject(MchWxmpUser.class);
mchWxmpUser.setUserId(userId);
MchWxmpUser dbRecord = mchWxmpUserService.getById(userId);
if (!getCurrentAgentNo().equals(dbRecord.getMchNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
if(!mchWxmpUserService.updateById(mchWxmpUser)) {
return ApiRes.fail(ApiCodeEnum.SYSTEM_ERROR, "更新失败");
}
return ApiRes.ok();
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 微信公众号消息接收者删除
*/
@PreAuthorize("hasAuthority('ENT_MCH_WXMP_USER_DELETE')")
@MethodLog(remark = "微信公众号消息接收者删除")
@DeleteMapping("/{userId}")
public ApiRes delete(@PathVariable("userId") Long userId) {
if(mchWxmpUserService.remove(MchWxmpUser.gw().eq(MchWxmpUser::getUserId, userId).eq(MchWxmpUser::getMchNo, getCurrentAgentNo()))) {
return ApiRes.ok();
}
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_DELETE);
}
}

View File

@@ -0,0 +1,261 @@
package com.jeequan.jeepay.agent.ctrl.order;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.JeepayClient;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.PayOrderCount;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.interfaces.device.IPrinterService;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.DBOSSConfig;
import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device;
import com.jeequan.jeepay.core.model.export.PayOrderExportExcel;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.core.utils.ExcelUtil;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.exception.JeepayException;
import com.jeequan.jeepay.model.PayOrderQueryReqModel;
import com.jeequan.jeepay.model.PayOrderQueryResModel;
import com.jeequan.jeepay.request.PayOrderQueryRequest;
import com.jeequan.jeepay.response.PayOrderQueryResponse;
import com.jeequan.jeepay.service.impl.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.*;
/**
* 支付订单管理类
*
* @author zhuxiao
* @site https://www.jeequan.com
* @date 2021-04-27 15:50
*/
@RestController
@RequestMapping("/api/payOrder")
public class PayOrderController extends CommonCtrl {
@Autowired private PayOrderService payOrderService;
@Autowired private PayWayService payWayService;
@Autowired private SysConfigService sysConfigService;
@Autowired private MchStoreDeviceService mchStoreDeviceService;
@Autowired private AgentInfoService agentInfoService;
@Autowired private OrderProfitSettRecordService orderProfitSettRecordService;
@Autowired private StatsTradeService statsTradeService;
@Autowired private MchAppService mchAppService;
/**
* @Author: ZhuXiao
* @Description: 订单信息列表
* @Date: 10:43 2021/5/13
*/
@PreAuthorize("hasAuthority('ENT_ORDER_LIST')")
@GetMapping
public ApiRes list() {
PayOrder payOrder = getObject(PayOrder.class);
JSONObject paramJSON = getReqParamJSON();
if (StringUtils.isEmpty(payOrder.getAgentNo())) {
List<String> allSubAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
payOrder.setSubAgentNoList(allSubAgentNoList);
}else {
if ("onlyOne".equals(payOrder.getAgentNo())) {
payOrder.setAgentNo(getCurrentAgentNo());
}
}
IPage<PayOrder> pages = payOrderService.listByPage(getIPage(), payOrder, paramJSON);
return ApiRes.page(pages);
}
/**
* @Author: ZhuXiao
* @Description: 支付订单信息
* @Date: 10:43 2021/5/13
*/
@PreAuthorize("hasAuthority('ENT_PAY_ORDER_VIEW')")
@GetMapping("/{payOrderId}")
public ApiRes detail(@PathVariable("payOrderId") String payOrderId) {
PayOrder payOrder = payOrderService.getDetails(payOrderId);
if (payOrder == null) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
List<String> allSubAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
if (!allSubAgentNoList.contains(payOrder.getAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
if (StringUtils.isNotBlank(payOrder.getChannelOrderNo())) {
DBOSSConfig ossConfig = sysConfigService.getOssConfig();
payOrder.addExt("channelOrderNoBar", ossConfig.getOssPublicSiteUrl() + "/bar/" + payOrder.getChannelOrderNo());
}
// 查询订单分润情况
List<OrderProfitSettRecord> profitList = orderProfitSettRecordService.getBaseMapper().queryOrderProfitSum(payOrderId, getCurrentAgentNo(), CS.SYS_ROLE_TYPE.AGENT);
payOrder.addExt("profitAmount", profitList.isEmpty() ? null : profitList.get(0).getCalProfitAmount());
return ApiRes.ok(payOrder);
}
/**
* @author: xiaoyu
* @date: 2022/2/10 17:00
* @describe: 订单列表统计
*/
@PreAuthorize("hasAuthority('ENT_ORDER_COUNT')")
@RequestMapping(value="/count", method = RequestMethod.GET)
public ApiRes count() {
PayOrder payOrder = getObject(PayOrder.class);
List<String> allAgentNoList = null;
if (StringUtils.isEmpty(payOrder.getAgentNo())) {
allAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
}else if ("onlyOne".equals(payOrder.getAgentNo())) {
allAgentNoList = Arrays.asList(getCurrentAgentNo());
}else {
allAgentNoList = Arrays.asList(payOrder.getAgentNo());
}
payOrder.setAgentNo(null);
JSONObject paramJSON = getReqParamJSON();
paramJSON.put("allAgentNoList", allAgentNoList);
// 查询支付、退款金额 笔数
PayOrderCount orderCount = statsTradeService.selectTotalByTransaction(paramJSON, allAgentNoList);
return ApiRes.ok(orderCount);
}
/**
* @author: xiaoyu
* @date: 2022/1/14 9:45
* @describe: 订单列表数据导出
*/
@RequestMapping(value="/exportExcel", method = RequestMethod.GET)
public void exportExcel() {
try {
JSONObject paramJSON = getReqParamJSON();
PayOrder payOrder = getObject(PayOrder.class);
if (StringUtils.isEmpty(payOrder.getAgentNo())) {
List<String> allSubAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
payOrder.setSubAgentNoList(allSubAgentNoList);
}else if ("onlyOne".equals(payOrder.getAgentNo())) {
payOrder.setAgentNo(getCurrentAgentNo());
}else {
payOrder.setAgentNo(payOrder.getAgentNo());
}
payOrder.setAgentNo(null);
IPage<PayOrder> pages = payOrderService.listByPage(getIPage(true), payOrder, paramJSON);
List<JSONObject> newList = new LinkedList<>();
for (PayOrder order:pages.getRecords()) {
JSONObject object = (JSONObject) JSONObject.toJSON(order);
object.put("amount", AmountUtil.convertCent2Dollar(order.getAmount()));
object.put("refundAmount", AmountUtil.convertCent2Dollar(order.getRefundAmount()));
object.put("mchFeeAmount", AmountUtil.convertCent2Dollar(order.getMchFeeAmount()));
object.put("mchOrderFeeAmount", AmountUtil.convertCent2Dollar(order.getMchOrderFeeAmount()));
newList.add(object);
}
List<PayOrderExportExcel> linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), PayOrderExportExcel.class);
// excel输出
ExcelUtil.exportExcel(linkedList, "支付订单", "支付订单", PayOrderExportExcel.class, "支付订单", response);
}catch (Exception e) {
logger.error("导出excel失败", e);
throw new BizException("导出订单失败!");
}
}
/**
* @Author: ZhuXiao
* @Description: 订单打印
* @Date: 10:43 2022/01/13
*/
@PreAuthorize("hasAuthority('ENT_PAY_ORDER_VIEW')")
@GetMapping("/print/{payOrderId}")
public ApiRes print(@PathVariable("payOrderId") String payOrderId) {
PayOrder payOrder = payOrderService.getById(payOrderId);
if (payOrder == null) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
if (!payOrder.getAgentNo().equals(getCurrentAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
PayOrderInfo4Device printPayOrderInfo = new PayOrderInfo4Device();
BeanUtil.copyProperties(payOrder, printPayOrderInfo);
try {
// 查询打印设备
List<JSONObject> deviceList = mchStoreDeviceService.selectAvailableDeviceList(payOrder.getMchNo(), payOrder.getStoreId(), Arrays.asList(DeviceProvideConfig.DEVICE_TYPE_PRINTER));
if (CollectionUtils.isEmpty(deviceList)) {
return ApiRes.customFail("打印机未配置");
}
// 循环调用单个设备
for (JSONObject deviceParams : deviceList) {
// 设备类型
String provider = deviceParams.getString("provider");
IPrinterService printerService = SpringBeansUtil.getBean(provider + "PrinterService", IPrinterService.class);
printerService.send(deviceParams, printPayOrderInfo);
}
return ApiRes.ok();
} catch (BizException e) {
throw e;
}
}
@MethodLog(remark = "订单状态刷新")
@PreAuthorize("hasAuthority('ENT_PAY_ORDER_REFRESH')")
@PostMapping("/refresh/{payOrderId}")
public ApiRes refresh(@PathVariable("payOrderId") String payOrderId) {
PayOrder payOrder = payOrderService.getById(payOrderId);
if(payOrder == null){
throw new BizException("订单数据异常");
}
if(PayOrder.STATE_ING != payOrder.getState()){
throw new BizException("订单状态不支持该操作");
}
MchAppEntity mchAppEntity = mchAppService.getById(payOrder.getAppId());
PayOrderQueryRequest request = new PayOrderQueryRequest();
PayOrderQueryReqModel model = new PayOrderQueryReqModel();
model.setPas(SysConfigService.PLATFORM_API_SECRET); // 通信秘钥
model.setMchNo(payOrder.getMchNo()); // 商户号
model.setAppId(payOrder.getAppId());
model.setPayOrderId(payOrderId);
request.setBizModel(model);
JeepayClient jeepayClient = new JeepayClient(sysConfigService.getDBApplicationConfig().getPaySiteUrl(), mchAppEntity.getAppSecret());
try {
PayOrderQueryResponse response = jeepayClient.execute(request);
if(response.getCode() != 0){
throw new BizException(response.getMsg());
}
PayOrderQueryResModel respData = response.get();
if(respData.getState() == PayOrder.STATE_SUCCESS){
return ApiRes.ok("订单刷新成功");
}
return ApiRes.customFail("订单状态一致,无需当前操作");
} catch (JeepayException e) {
throw new BizException(e.getMessage());
}
}
}

View File

@@ -0,0 +1,161 @@
package com.jeequan.jeepay.agent.ctrl.order;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.entity.PayOrderCount;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.export.MchRefundOrderExportExcel;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.core.utils.ExcelUtil;
import com.jeequan.jeepay.db.entity.RefundOrder;
import com.jeequan.jeepay.service.impl.AgentInfoService;
import com.jeequan.jeepay.service.impl.RefundOrderService;
import com.jeequan.jeepay.service.impl.StatsTradeService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/***
* 退款订单管理
*
* @author terrfly
* @date 2022/3/16 20:37
*/
@RestController
@RequestMapping("/api/refundOrder")
public class RefundOrderController extends CommonCtrl {
@Autowired private RefundOrderService refundOrderService;
@Autowired private AgentInfoService agentInfoService;
@Autowired
private StatsTradeService statsTradeService;
/**
* @Author: ZhuXiao
* @Description: 退款订单信息列表
* @Date: 10:44 2021/5/13
*/
@PreAuthorize("hasAuthority('ENT_REFUND_LIST')")
@GetMapping
public ApiRes list() {
RefundOrder refundOrder = getObject(RefundOrder.class);
JSONObject paramJSON = getReqParamJSON();
LambdaQueryWrapper<RefundOrder> wrapper = RefundOrder.gw();
if (StringUtils.isEmpty(refundOrder.getAgentName())) {
List<String> allSubAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
wrapper.in(RefundOrder::getAgentNo, allSubAgentNoList);
}else {
if ("onlyOne".equals(refundOrder.getAgentNo())) {
//refundOrder.setAgentNo(getCurrentAgentNo());
refundOrder.setAgentName(getCurrentAgentNo());
}
}
IPage<RefundOrder> pages = refundOrderService.pageList(getIPage(), wrapper, refundOrder, paramJSON);
setIfName(pages.getRecords());
return ApiRes.page(pages);
}
/**
* @Author: ZhuXiao
* @Description: 退款订单信息
* @Date: 10:44 2021/5/13
*/
@PreAuthorize("hasAuthority('ENT_REFUND_ORDER_VIEW')")
@GetMapping("/{refundOrderId}")
public ApiRes detail(@PathVariable("refundOrderId") String refundOrderId) {
RefundOrder refundOrder = refundOrderService.getById(refundOrderId);
if (refundOrder == null) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
List<String> allSubAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
if (!allSubAgentNoList.contains(refundOrder.getAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
return ApiRes.ok(refundOrder);
}
/**
* @author: xiaoyu
* @date: 2022/1/14 9:45
* @describe: 退款列表数据导出
*/
@RequestMapping(value="/exportExcel", method = RequestMethod.GET)
public void exportExcel() {
try {
JSONObject paramJSON = getReqParamJSON();
LambdaQueryWrapper<RefundOrder> wrapper = RefundOrder.gw();
RefundOrder refundOrder = getObject(RefundOrder.class);
if (StringUtils.isEmpty(refundOrder.getAgentNo())) {
List<String> allSubAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
wrapper.in(RefundOrder::getAgentNo, allSubAgentNoList);
}else if ("onlyOne".equals(refundOrder.getAgentNo())) {
wrapper.in(RefundOrder::getAgentNo, getCurrentAgentNo());
}else {
wrapper.in(RefundOrder::getAgentNo, refundOrder.getAgentNo());
}
refundOrder.setAgentNo(null);
IPage<RefundOrder> pages = refundOrderService.pageList(getIPage(true), wrapper, refundOrder, paramJSON);
List<JSONObject> newList = new LinkedList<>();
for (RefundOrder order:pages.getRecords()) {
JSONObject object = (JSONObject) JSONObject.toJSON(order);
object.put("payAmount", AmountUtil.convertCent2Dollar(order.getPayAmount()));
object.put("refundAmount", AmountUtil.convertCent2Dollar(order.getRefundAmount()));
object.put("refundFeeAmount", AmountUtil.convertCent2Dollar(order.getRefundFeeAmount()));
newList.add(object);
}
List<MchRefundOrderExportExcel> linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), MchRefundOrderExportExcel.class);
// excel输出
ExcelUtil.exportExcel(linkedList, "退款订单", "退款订单", MchRefundOrderExportExcel.class, "退款订单", response);
}catch (Exception e) {
logger.error("导出excel失败", e);
throw new BizException("导出订单失败!");
}
}
/**
* @author: xiaoyu
* @date: 2022/2/10 17:00
* @describe: 退款列表统计
*/
@PreAuthorize("hasAuthority('ENT_REFUND_ORDER_COUNT')")
@RequestMapping(value = "/count", method = RequestMethod.GET)
public ApiRes count() {
RefundOrder refundOrder = getObject(RefundOrder.class);
List<String> allAgentNoList = null;
if (StringUtils.isEmpty(refundOrder.getAgentNo())) {
allAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
} else if ("onlyOne".equals(refundOrder.getAgentNo())) {
allAgentNoList = Collections.singletonList(getCurrentAgentNo());
} else {
allAgentNoList = Collections.singletonList(refundOrder.getAgentNo());
}
refundOrder.setAgentNo(null);
JSONObject paramJSON = getReqParamJSON();
paramJSON.put("allAgentNoList", allAgentNoList);
// 查询支付、退款金额 笔数
PayOrderCount resMap = statsTradeService.selectTotalByTransaction(paramJSON, allAgentNoList);
return ApiRes.ok(resMap);
}
}

View File

@@ -0,0 +1,125 @@
package com.jeequan.jeepay.agent.ctrl.order;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.export.MchTransferOrderExportExcel;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.core.utils.ExcelUtil;
import com.jeequan.jeepay.db.entity.TransferOrderEntity;
import com.jeequan.jeepay.service.impl.TransferOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* 转账订单api
*
* @author terrfly
*
* @date 2021/8/13 10:52
*/
@RestController
@RequestMapping("/api/transferOrders")
public class TransferOrderController extends CommonCtrl {
@Autowired private TransferOrderService transferOrderService;
/** list **/
@PreAuthorize("hasAuthority('ENT_TRANSFER_ORDER_LIST')")
@RequestMapping(value="", method = RequestMethod.GET)
public ApiRes list() {
TransferOrderEntity transferOrder = getObject(TransferOrderEntity.class);
// 可查看自己和全部下级代理数据
String currentAgentNo = getCurrentAgentNo();
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
// 自己和下级服务商
if (CollUtil.isNotEmpty(subAgentNoList)){
transferOrder.setSubAgentNoList(subAgentNoList);
}
IPage<TransferOrderEntity> pages = transferOrderService.pageList(getIPage(), transferOrder);
return ApiRes.page(pages);
}
/** detail **/
/*@PreAuthorize("hasAuthority('ENT_TRANSFER_ORDER_VIEW')")
@RequestMapping(value="/{recordId}", method = RequestMethod.GET)
public ApiRes detail(@PathVariable("recordId") String transferId) {
TransferOrderEntity refundOrder = transferOrderService.queryMchOrder(getCurrentMchNo(), null, transferId);
if (refundOrder == null) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
return ApiRes.ok(refundOrder);
}*/
/**
* @author: xiaoyu
* @date: 2022/1/14 9:45
* @describe: 转账数据导出
*/
@RequestMapping(value="/exportExcel", method = RequestMethod.GET)
public void exportExcel() {
try {
TransferOrderEntity transferOrder = getObject(TransferOrderEntity.class);
transferOrder.setAgentNo(getCurrentAgentNo());
IPage<TransferOrderEntity> pages = transferOrderService.pageList(getIPage(true), transferOrder);
List<JSONObject> newList = new LinkedList<>();
for (TransferOrderEntity order:pages.getRecords()) {
JSONObject object = (JSONObject) JSONObject.toJSON(order);
object.put("entryType", order.getEntryType().replaceAll("_",""));
object.put("amount", AmountUtil.convertCent2Dollar(order.getAmount()));
newList.add(object);
}
List<MchTransferOrderExportExcel> linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), MchTransferOrderExportExcel.class);
// excel输出
ExcelUtil.exportExcel(linkedList, "转账订单", "转账订单", MchTransferOrderExportExcel.class, "转账订单", response);
}catch (Exception e) {
logger.error("导出excel失败", e);
throw new BizException("导出订单失败!");
}
}
/**
* @author: xiaoyu
* @date: 2023/4/26 14:55
* @describe: 数据统计
*/
@PreAuthorize("hasAuthority('ENT_TRANSFER_ORDER_COUNT')")
@RequestMapping(value="/count", method = RequestMethod.GET)
public ApiRes count() {
TransferOrderEntity transferOrder = getObject(TransferOrderEntity.class);
LambdaQueryWrapper<TransferOrderEntity> wrapper = TransferOrderEntity.gw();
// 可查看自己和全部下级代理数据
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
// 自己和下级服务商
if (CollUtil.isNotEmpty(subAgentNoList)){
transferOrder.setSubAgentNoList(subAgentNoList);
}
transferOrder.setState(null);
// 条件参数
transferOrderService.selectParams(wrapper, transferOrder);
Map result = transferOrderService.queryCount(wrapper);
return ApiRes.ok(result);
}
}

View File

@@ -0,0 +1,145 @@
package com.jeequan.jeepay.agent.ctrl.payconfig;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.bizcommons.manage.MchPayPassageConfigManage;
import com.jeequan.jeepay.components.mq.vender.IMQSender;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.applyment.ApplymentBasicInfo;
import com.jeequan.jeepay.core.model.applyment.PaywayFee;
import com.jeequan.jeepay.core.utils.JsonKit;
import com.jeequan.jeepay.db.entity.MchApplyment;
import com.jeequan.jeepay.db.entity.MchPayPassage;
import com.jeequan.jeepay.service.impl.MchApplymentService;
import com.jeequan.jeepay.service.impl.MchPayPassageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/****
* 新版商户支付通道配置ctrl
*
* @author terrfly
*
* @date 2022/3/30 16:37
*/
@RestController
@RequestMapping("/api/mch/payPassages")
public class MchPayPassageConfigController extends CommonCtrl {
@Autowired private MchPayPassageService mchPayPassageService;
@Autowired private MchPayPassageConfigManage mchPayPassageConfigManage;
@Autowired
private MchApplymentService mchApplymentService;
@Autowired
private IMQSender mqSender;
/**
* 支付方式 <--> 通道配置
* 左侧列表(支付方式)
*
* **/
@GetMapping
public ApiRes list() {
String appId = getValStringRequired("appId");
String wayCode = getValString("wayCode");
String wayName = getValString("wayName");
String unionSearchId = getValString("unionSearchId");
return mchPayPassageConfigManage.queryPaywayList(appId, wayCode, wayName, null, unionSearchId, getIPage());
}
/**
* 支付方式 <--> 通道配置
* 右侧列表(可用的支付接口)
*
* **/
@GetMapping("/availablePayInterface/{appId}/{wayCode}")
public ApiRes availablePayInterface(@PathVariable("appId") String appId, @PathVariable("wayCode") String wayCode) {
return mchPayPassageConfigManage.availablePayInterface(appId, wayCode);
}
/**
* 更新商户使用的通道信息
*/
@PostMapping("/mchPassage")
@MethodLog(remark = "更新商户支付通道")
public ApiRes updatePassage() {
String appId = getValStringRequired("appId");
String ifCode = getValStringRequired("ifCode");
String wayCode = getValStringRequired("wayCode");
Byte state = getValByteRequired("state");
mchPayPassageService.updateMchPassageState(appId, wayCode, ifCode, state);
return ApiRes.ok();
}
/**
* 查询商户应用支付通道是否配置
* 用于进件成功一键配置到应用,点击按钮时检查进件记录中包含的支付方式是否在该应用下已配置其他渠道
*/
@GetMapping("/exist/{applyId}/{appId}")
public ApiRes exist(@PathVariable("applyId") String applyId, @PathVariable("appId") String appId) {
MchApplyment tbMchApplyment = mchApplymentService.getById(applyId);
if (tbMchApplyment == null || tbMchApplyment.getState() != MchApplyment.STATE_SUCCESS) {
return ApiRes.customFail("进件记录不存在或进件状态未成功");
}
// 获取当前进件记录费率配置
ApplymentBasicInfo applymentBasicInfo = JSONObject.parseObject(tbMchApplyment.getApplyDetailInfo(), ApplymentBasicInfo.class);
// 费率
List<PaywayFee> paywayFeeList = applymentBasicInfo.getPaywayFeeList();
// 费率为空,进件成功一键配置到应用将不执行配置费率和通道,可直接返回
if (CollUtil.isEmpty(paywayFeeList)) {
return ApiRes.ok();
}
// 获取费率配置的支付方式
List<String> wayCodeList = new ArrayList<>();
paywayFeeList.forEach(paywayFee -> {
wayCodeList.add(paywayFee.getWayCode());
});
// 支付方式已配置其他渠道
List<MchPayPassage> payPassages = mchPayPassageService.list(MchPayPassage.gw()
.eq(MchPayPassage::getAppId, appId)
.ne(MchPayPassage::getIfCode, tbMchApplyment.getIfCode())
.in(MchPayPassage::getWayCode, wayCodeList));
if (CollUtil.isNotEmpty(payPassages)) {
return ApiRes.ok(JsonKit.newJson("existMchPayPassage", CS.YES));
}
return ApiRes.ok();
}
/**
* 进件成功一键配置到应用,更新商户支付通道
*/
@MethodLog(remark = "进件成功,一键配置商户支付信息")
@PostMapping("/applyment/{applyId}/{appId}")
public ApiRes updateMchPayPassageByApplyment(@PathVariable("applyId") String applyId, @PathVariable("appId") String appId) {
// AutoConfigMchAppPayInfoResult result = mchApplymentService.autoConfigMchAppPayInfo(applyId, appId, getValByteRequired("isOverWrite") == CS.YES);
//
// if (StringUtils.isNotBlank(result.getErrMsg())) {
// return ApiRes.customFail(result.getErrMsg());
// }
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,282 @@
package com.jeequan.jeepay.agent.ctrl.payconfig;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.IsvUserConn;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.params.IsvParams;
import com.jeequan.jeepay.core.model.params.NormalMchParams;
import com.jeequan.jeepay.core.utils.StringKit;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.service.impl.IsvInfoService;
import com.jeequan.jeepay.service.impl.MchAppService;
import com.jeequan.jeepay.service.impl.PayInterfaceConfigService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.*;
/***
* 支付配置
*
* @author terrfly
*
* @date 2022/3/21 0:13
*/
@RestController
@RequestMapping("/api/payConfig")
public class PayConfigController extends CommonCtrl {
@Autowired
private MchAppService mchAppService;
@Autowired
private PayInterfaceConfigService payInterfaceConfigService;
@Autowired
private IsvInfoService isvInfoService;
/**
* 查询可用的支付接口
* <p>
* 使用功能项目: 参数及费率的填写
* 服务商查询全部支付接口
* 服务商查询服务商开启的支付接口
**/
@PreAuthorize("hasAnyAuthority('ENT_PC', 'ENT_AGENT_RATE_CONFIG', 'ENT_MCH_APPLYMENT')")
@GetMapping("/ifCodes")
public ApiRes ifCodes() {
// 搜索条件
String ifName = getValString("ifName");
String infoId = getValStringRequired("infoId"); // infoId
String configMode = getValStringRequired("configMode"); // 设置类型
// 支付接口列表
LambdaQueryWrapper<PayInterfaceDefine> lambdaQueryWrapper = PayInterfaceDefine.gw();
lambdaQueryWrapper.eq(PayInterfaceDefine::getState, CS.YES); // 查询可用的支付接口列表
lambdaQueryWrapper.like(StringUtils.isNotEmpty(ifName), PayInterfaceDefine::getIfName, ifName);
AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());
Map<String, IsvUserConn> ifCodeMap = new HashMap<>();
// 服务商 配置 商户费率 | 下级服务商费率 | 自己配置信息 【显示 当前服务商所有接口】
if (RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode) ||
RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode) ||
RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)
) {
ifCodeMap = isvInfoService.getIsvUserConn(CS.SYS_ROLE_TYPE.AGENT, agentInfo.getAgentNo(), CS.YES);
List<String> ifCodeList = new ArrayList<>(ifCodeMap.keySet());
if (ifCodeList.isEmpty()) { // 没有可用的接口
return ApiRes.ok(ifCodeList);
}
lambdaQueryWrapper.in(PayInterfaceDefine::getIfCode, ifCodeList);
} else if (RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode)) { // 服务商进件
// 查询 当前服务商 开通的
ifCodeMap = isvInfoService.getIsvUserConn(CS.SYS_ROLE_TYPE.AGENT, agentInfo.getAgentNo(), null);
if (ifCodeMap.isEmpty()) { // 没有可用的接口
return ApiRes.ok(Collections.emptyList());
}
lambdaQueryWrapper.in(PayInterfaceDefine::getIfCode, ifCodeMap.keySet());
lambdaQueryWrapper.eq(PayInterfaceDefine::getIsSupportApplyment, CS.YES); // 查询支持进件的接口
}
final List<PayInterfaceDefine> list = new ArrayList<>();
lambdaQueryWrapper.orderByAsc(PayInterfaceDefine::getCreatedAt);
final Map<String, IsvUserConn> finalMap = ifCodeMap;
payInterfaceDefineService.list(lambdaQueryWrapper).forEach(item -> {
// 如果服务商上级配置的开启进件为关闭,那么最终展示的列表中显示的是否开启进件也为关闭
IsvUserConn ifCodeInfo = finalMap.get(item.getIfCode());
boolean isEnabled = ifCodeInfo.getStatus() == CS.YES && ifCodeInfo.getConfigStatus() == CS.YES;
item.addExt("configState", ifCodeInfo.getStatus());
item.setState(isEnabled ? CS.YES : CS.NO);
list.add(item);
});
return ApiRes.ok(list);
}
/**
* 查询已经配置的参数信息
**/
@PreAuthorize("hasAuthority('ENT_MCH_APP_PAY_CONFIG')")
@GetMapping(value = "/interfaceSavedConfigs")
public ApiRes interfaceSavedConfigs() {
String ifCode = getValStringRequired("ifCode"); // ifCode
String infoId = getValStringRequired("infoId"); // infoId
String configMode = getValStringRequired("configMode"); // 设置类型
PayInterfaceDefine payInterfaceDefine = payInterfaceDefineService.getById(ifCode);
String infoType = null;
JSONArray ifDefineArray = null;
Byte mchType = null; // 商户类型
Byte isvIsOpenApplyment = 0; // 服务商是否开启进件
// 服务商 配置商户应用信息
if (RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode)) {
infoType = CS.SYS_ROLE_TYPE.MCH_APP;
MchInfo mchInfo = mchInfoService.getById(mchAppService.getById(infoId).getMchNo());
mchType = mchInfo.getType();
if (mchType == CS.MCH_TYPE_NORMAL) {
ifDefineArray = JSON.parseArray(payInterfaceDefine.getNormalMchParams());
} else {
ifDefineArray = JSON.parseArray(payInterfaceDefine.getIsvsubMchParams());
}
}
// 服务商 配置下级服务商信息
else if (RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode) || RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)) {
infoType = CS.SYS_ROLE_TYPE.AGENT;
if ("CURRENTAGENT".equals(infoId)) {
infoId = getCurrentAgentNo();
}
AgentInfo agentInfo = agentInfoService.getById(infoId);
if (agentInfo != null && StringUtils.isNotBlank(agentInfo.getIsvNo())) {
PayInterfaceConfig isvIfConfig = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.ISV, agentInfo.getIsvNo(), ifCode);
isvIsOpenApplyment = isvIfConfig != null ? isvIfConfig.getIsOpenApplyment() : 0;
}
}
// 查询已经配置的信息
PayInterfaceConfig payInterfaceConfig = payInterfaceConfigService.getByInfoIdAndIfCode(infoType, infoId, ifCode);
if (payInterfaceConfig == null) {
payInterfaceConfig = new PayInterfaceConfig();
}
// 处理脱敏数据
if (StringUtils.isNotEmpty(payInterfaceConfig.getIfParams())) {
if (RateConfig.CONFIG_MODE_MGRISV.equals(configMode)) {
IsvParams isvParams = IsvParams.factory(ifCode, payInterfaceConfig.getIfParams());
if (isvParams != null) {
payInterfaceConfig.setIfParams(isvParams.deSenData());
}
} else if (RateConfig.CONFIG_MODE_MGRMCH.equals(configMode)) {
if (mchType == CS.MCH_TYPE_NORMAL) {
NormalMchParams isvParams = NormalMchParams.factory(ifCode, payInterfaceConfig.getIfParams());
if (isvParams != null) {
payInterfaceConfig.setIfParams(isvParams.deSenData());
}
} else {
}
}
}
payInterfaceConfig.addExt("ifDefineArray", ifDefineArray);
payInterfaceConfig.addExt("mchType", mchType);
payInterfaceConfig.addExt("configPageType", payInterfaceDefine.getConfigPageType());
payInterfaceConfig.addExt("isSupportApplyment", payInterfaceDefine.getIsSupportApplyment()); // 支付接口是否支持进件
payInterfaceConfig.addExt("isvIsOpenApplyment", isvIsOpenApplyment); // 上级服务商是否开启进件
return ApiRes.ok(payInterfaceConfig);
}
/**
* 更新支付参数
**/
@PreAuthorize("hasAuthority('ENT_MCH_APP_PAY_CONFIG')")
@PostMapping("/interfaceParams")
@MethodLog(remark = "更新支付参数")
public ApiRes saveOrUpdate() {
PayInterfaceConfig payInterfaceConfig = getObject(PayInterfaceConfig.class);
String configMode = payInterfaceConfig.extv().getString("configMode"); // 设置类型
String infoType = null;
if (RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode)) {
infoType = CS.SYS_ROLE_TYPE.MCH_APP;
}
// 服务商 配置下级服务商
else if (RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode) || RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)) {
infoType = CS.SYS_ROLE_TYPE.AGENT;
if ("CURRENTAGENT".equals(payInterfaceConfig.getInfoId())) {
payInterfaceConfig.setInfoId(getCurrentAgentNo());
}
}
payInterfaceConfig.setInfoType(infoType);
//添加更新者信息
Long userId = getCurrentUser().getSysUser().getSysUserId();
String realName = getCurrentUser().getSysUser().getRealname();
payInterfaceConfig.setUpdatedUid(userId);
payInterfaceConfig.setUpdatedBy(realName);
//根据 服务商号、接口类型 获取商户参数配置
PayInterfaceConfig dbRecoed = payInterfaceConfigService.getByInfoIdAndIfCode(payInterfaceConfig.getInfoType(), payInterfaceConfig.getInfoId(), payInterfaceConfig.getIfCode());
//若配置存在为saveOrUpdate添加ID第一次配置添加创建者
if (dbRecoed != null) {
payInterfaceConfig.setId(dbRecoed.getId());
// 合并支付参数
payInterfaceConfig.setIfParams(StringKit.marge(dbRecoed.getIfParams(), payInterfaceConfig.getIfParams(), dbRecoed.getIfCode()));
} else {
payInterfaceConfig.setCreatedUid(userId);
payInterfaceConfig.setCreatedBy(realName);
}
boolean result = payInterfaceConfigService.saveOrUpdate(payInterfaceConfig);
if (!result) {
return ApiRes.fail(ApiCodeEnum.SYSTEM_ERROR, "配置失败");
}
return ApiRes.ok();
}
/**
* 查询商户应用支付参数、费率是否配置
* 用于发起进件 自动配置到应用时的提示
*/
@GetMapping("/existPayParams/{appId}/{ifCode}")
public ApiRes existPayParams(@PathVariable("appId") String appId, @PathVariable("ifCode") String ifCode) {
// Integer range = getValInteger("range");
// String mccCode = getValString("mccCode");
// String isvNo = getValString("isvNo");
//
// // 应用参数配置
// PayInterfaceConfig interfaceConfig = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.MCH_APP, appId, ifCode);
// if (interfaceConfig == null) {
// return ApiRes.ok();
// }
//
// if (StringUtils.isNotBlank(interfaceConfig.getIfParams()) && !interfaceConfig.getIfParams().equals("{}")) {
// return ApiRes.ok(JsonKit.newJson("existMchParams", CS.YES));
// }
//
// // 费率配置
// Map<String, PaywayFee> paywayFeeMap = rateConfigService.queryPaywayFeeMap(appId + "_" + RateConfig.MCHRATE, CS.SYS_ROLE_TYPE.MCH_APP, ifCode, range, mccCode, isvNo);
// if (paywayFeeMap != null && StringUtils.isNotBlank(interfaceConfig.getIfParams()) && !interfaceConfig.getIfParams().equals("{}")) {
// return ApiRes.ok(JsonKit.newJson("existMchParams", CS.YES));
// }
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,58 @@
package com.jeequan.jeepay.agent.ctrl.payconfig;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.PayInterfaceDefine;
import com.jeequan.jeepay.service.impl.PayInterfaceDefineService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 支付接口定义管理类
*
* @author zhuxiao
*
* @date 2021-04-27 15:50
*/
@RestController
@RequestMapping("api/payIfDefines")
public class PayInterfaceDefineController extends CommonCtrl {
@Autowired private PayInterfaceDefineService payInterfaceDefineService;
/**
* @Author: ZhuXiao
* @Description: list
* @Date: 15:51 2021/4/27
*/
@GetMapping
public ApiRes list() {
PayInterfaceDefine queryRecord = getObject(PayInterfaceDefine.class);
LambdaQueryWrapper<PayInterfaceDefine> lambdaQueryWrapper = PayInterfaceDefine.gw();
lambdaQueryWrapper.eq(queryRecord.getState() != null , PayInterfaceDefine::getState, queryRecord.getState());
lambdaQueryWrapper.eq(queryRecord.getIsSupportApplyment() != null , PayInterfaceDefine::getIsSupportApplyment, queryRecord.getIsSupportApplyment());
lambdaQueryWrapper.orderByAsc(PayInterfaceDefine::getCreatedAt);
List<PayInterfaceDefine> list = payInterfaceDefineService.list(lambdaQueryWrapper);
return ApiRes.ok(list);
}
/**
* @Author: ZhuXiao
* @Description: detail
* @Date: 15:51 2021/4/27
*/
@GetMapping("/{ifCode}")
public ApiRes detail(@PathVariable("ifCode") String ifCode) {
return ApiRes.ok(payInterfaceDefineService.getById(ifCode));
}
}

View File

@@ -0,0 +1,59 @@
package com.jeequan.jeepay.agent.ctrl.payconfig;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.PayWay;
import com.jeequan.jeepay.service.impl.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 支付方式配置类
*
* @author zhuxiao
*
* @date 2021-04-27 15:50
*/
@RestController
@RequestMapping("/api/payWays")
public class PayWayController extends CommonCtrl {
@Autowired PayWayService payWayService;
@Autowired MchPayPassageService mchPayPassageService;
@Autowired PayOrderService payOrderService;
@Autowired MchInfoService mchInfoService;
@Autowired PayInterfaceConfigService payInterfaceConfigService;
/**
* @Author: ZhuXiao
* @Description: list
* @Date: 15:52 2021/4/27
*/
@PreAuthorize("hasAuthority('ENT_PAY_ORDER_SEARCH_PAY_WAY')")
@GetMapping
public ApiRes list() {
PayWay queryObject = getObject(PayWay.class);
LambdaQueryWrapper<PayWay> condition = PayWay.gw();
if(StringUtils.isNotEmpty(queryObject.getWayCode())){
condition.like(PayWay::getWayCode, queryObject.getWayCode());
}
if(StringUtils.isNotEmpty(queryObject.getWayName())){
condition.like(PayWay::getWayName, queryObject.getWayName());
}
condition.orderByAsc(PayWay::getWayCode);
IPage<PayWay> pages = payWayService.page(getIPage(true), condition);
return ApiRes.page(pages);
}
}

View File

@@ -0,0 +1,46 @@
package com.jeequan.jeepay.agent.ctrl.payconfig;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.QualificationDefineEntity;
import com.jeequan.jeepay.service.impl.QualificationDefineService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RequestMapping("/api/qualificationDefine")
@RestController
public class QualificationDefineController extends CommonCtrl {
@Autowired
private QualificationDefineService qualificationDefineService;
@PostMapping("/save")
public ApiRes save() {
QualificationDefineEntity entity = getObject(QualificationDefineEntity.class);
boolean save = qualificationDefineService.save(entity);
return ApiRes.ok(save);
}
@GetMapping("/page")
public ApiRes page() {
Page<QualificationDefineEntity> iPage = getIPage(false);
QualificationDefineEntity condition = getObject(QualificationDefineEntity.class);
qualificationDefineService.lambdaQuery().setEntity(condition).page(iPage);
return ApiRes.ok(iPage);
}
@GetMapping("/{code}")
public ApiRes one(@PathVariable String code) {
QualificationDefineEntity one = qualificationDefineService.lambdaQuery().eq(QualificationDefineEntity::getCode, code).one();
return ApiRes.ok(one);
}
@DeleteMapping("/{code}")
public ApiRes del(@PathVariable String code) {
qualificationDefineService.removeById(code);
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,657 @@
package com.jeequan.jeepay.agent.ctrl.payconfig;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.converter.BaseConverter;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.applyment.PaywayFee;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.model.RateConfigSimple;
import com.jeequan.jeepay.service.impl.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
/***
* 费率配置信息
*
* @author terrfly
*
* @date 2022/3/21 0:13
*/
@RestController
@RequestMapping("/api/rateConfig")
public class RateConfigController extends CommonCtrl {
@Autowired private MchAppService mchAppService;
@Autowired private RateConfigService rateConfigService;
@Autowired private PayWayService payWayService;
@Autowired private PayInterfaceConfigService payInterfaceConfigService;
@Autowired
private BaseConverter baseConverter;
@Autowired
private RateConfigV2Service rateConfigV2Service;
/** 查询可用的支付接口 **/
@GetMapping("/ifCodes")
public ApiRes ifCodes() {
// 搜索条件
String ifName = getValString("ifName");
String infoId = getValStringRequired("infoId"); // infoId
String configMode = getValStringRequired("configMode"); // 设置类型
// 支付接口列表
LambdaQueryWrapper<PayInterfaceDefine> lambdaQueryWrapper = PayInterfaceDefine.gw();
lambdaQueryWrapper.eq(PayInterfaceDefine::getState, CS.YES); // 查询可用的支付接口列表
lambdaQueryWrapper.like(StringUtils.isNotEmpty(ifName), PayInterfaceDefine::getIfName, ifName);
AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());
// 服务商 配置 商户费率 | 下级服务商费率 | 自己配置信息 【显示 当前服务商所有接口】
if(RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode) ||
RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode)||
RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)
){
List<String> ifCodeList = new ArrayList<>();
payInterfaceConfigService.list(PayInterfaceConfig.gw().select(PayInterfaceConfig::getIfCode)
.eq(PayInterfaceConfig::getInfoId, agentInfo.getIsvNo())
.eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.ISV)
.eq(PayInterfaceConfig::getState, CS.YES)
).forEach(r -> ifCodeList.add(r.getIfCode()));
if(ifCodeList.isEmpty()){ // 没有可用的接口
return ApiRes.ok(ifCodeList);
}
lambdaQueryWrapper.in(PayInterfaceDefine::getIfCode, ifCodeList);
}else if( RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode) ){ // 服务商进件
// 查询服务商开通的
List<String> ifCodeList = new ArrayList<>();
List<PayInterfaceConfig> result = payInterfaceConfigService.list(PayInterfaceConfig.gw().select(PayInterfaceConfig::getIfCode)
.eq(PayInterfaceConfig::getInfoId, agentInfo.getIsvNo())
.eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.ISV)
.eq(PayInterfaceConfig::getState, CS.YES));
for (PayInterfaceConfig payInterfaceConfig : result) {
ifCodeList.add(payInterfaceConfig.getIfCode());
}
if(ifCodeList.isEmpty()){ // 没有可用的接口
return ApiRes.ok(ifCodeList);
}
// 查询服务商配置费率的支付接口
Set<String> agentIfCodes = new HashSet<>();
rateConfigService.lambdaQuery()
.select(RateConfig::getIfCode)
.eq(RateConfig::getInfoId, RateConfig.appendInfoByAgent(getCurrentAgentNo()))
.eq(RateConfig::getInfoType, CS.SYS_ROLE_TYPE.AGENT)
.in(RateConfig::getIfCode, ifCodeList)
.list().forEach(r -> agentIfCodes.add(r.getIfCode()));
//
Collection<String> ifCodeList1 = CollUtil.intersection(ifCodeList, agentIfCodes);
ifCodeList = new ArrayList<>(ifCodeList1);
if(ifCodeList.isEmpty()){ // 没有可用的接口
return ApiRes.ok(ifCodeList);
}
lambdaQueryWrapper.in(PayInterfaceDefine::getIfCode, ifCodeList);
}
lambdaQueryWrapper.orderByAsc(PayInterfaceDefine::getCreatedAt);
List<PayInterfaceDefine> list = payInterfaceDefineService.list(lambdaQueryWrapper);
return ApiRes.ok(list);
}
/** 查询所有可配置的支付方式 payways **/
@GetMapping("/payways")
public ApiRes payways() {
String ifCode = getValStringRequired("ifCode"); // ifCode
// String infoId = getValStringRequired("infoId"); // infoId
// String isvNo = getValStringRequired("isvNo"); // infoId
String isvNo = getValStringDefault("isvNo", "V1703659196"); // infoId
String configMode = getValStringRequired("configMode"); // 设置类型
Integer range = getValInteger("range");
String mccCode = getValString("mccCode");
String mchAppId = getValString("appId");
if (!ObjUtil.isEmpty(mchAppId)) {
MchAppEntity mchApp = mchAppService.getById(mchAppId);
range = mchApp.getRange();
mccCode = mchApp.getMccCode();
}
// 商户服务商或者服务商的父ID (用于过滤掉关闭的支付方式)
String belongAgentNo = null;
// 是否仅显示 支持进件的支付方式(用作进件使用)
boolean isOnlyApplymentSupport = false;
AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());
belongAgentNo = agentInfo.getAgentNo();
// 进件模式
if(RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode)){
isOnlyApplymentSupport = true;
}
IPage<PayWay> pages = payWayService.queryWayListByRate(ifCode, isvNo, belongAgentNo, isOnlyApplymentSupport, range, mccCode, isvNo);
return ApiRes.page(pages);
}
/** 查询当前已经配置的列表 **/
@GetMapping(value="/savedMapData")
public ApiRes savedMapData() {
String ifCode = getValStringRequired("ifCode"); // ifCode
String infoId = getValStringRequired("infoId"); // infoId
String configMode = getValStringRequired("configMode"); // 设置类型
// String isvNo = getValStringRequired("isvNo"); // 设置类型
String isvNo = getValStringDefault("isvNo", "V1703659196"); // 设置类型
Integer range = getValInteger("range");
String mccCode = getValString("mccCode");
String mchAppId = getValString("appId");
if (!ObjUtil.isEmpty(mchAppId)) {
MchAppEntity mchApp = mchAppService.getById(mchAppId);
range = mchApp.getRange();
mccCode = mchApp.getMccCode();
}
// 配置商户费率 || 服务商进件模式
if(RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode) || RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode)){
Map<String, Map<String, PaywayFee>> result = new HashMap<>();
String mchNo = "";
String applyId = "";
// 进件模式 : infoId = applyId_mchNo 的拼接方式。
if(RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode)){
applyId = infoId.split("_")[0];
mchNo = infoId.split("_")[1];
} else {
// MchAppEntity mchAppEntity = mchAppService.getById(infoId);
// mchNo = mchAppEntity.getMchNo();
mchNo = infoId;
}
Map<String, PaywayFee> mchRateMap = null;
// 查询已经配置的信息
if(RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode)){ // 运营平台进件模式
// mchRateMap = rateConfigService.queryPaywayFeeMapByApplyment(applyId);
// 此处费率不从商户信息里面取了
mchRateMap = rateConfigService.queryPaywayFeeMap(mchNo, CS.SYS_ROLE_TYPE.MCH_APPLYMENT, ifCode, range, mccCode, isvNo);
}else{
mchRateMap = rateConfigService.queryPaywayFeeMap(infoId + "_" + RateConfig.MCHRATE, commonGetInfoType(configMode), ifCode, range, mccCode, isvNo);
}
MchInfo mchInfo = mchInfoService.getById(mchNo);
Map<String, PaywayFee> parentDefRate = null;
// 特约商户
if(mchInfo.getType() == CS.MCH_TYPE_ISVSUB){
// 我的费率(商户上级服务商的费率)
result.put(RateConfig.READONLYPARENTAGENT, rateConfigService.queryPaywayFeeMap(mchInfo.getAgentNo() + "_" + RateConfig.AGENTRATE, CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo));
// 默认费率
parentDefRate = rateConfigService.queryPaywayFeeMap(mchInfo.getAgentNo() + "_" + RateConfig.MCHAPPLYDEF, CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo);
result.put(RateConfig.READONLYPARENTDEFRATE, parentDefRate);
}
// 商户费率为空时,将默认费率设置为商户费率
if (ObjUtil.isEmpty(mchRateMap)) {
mchRateMap = parentDefRate;
}
PaywayFee.resetData(mchRateMap, parentDefRate);
result.put(RateConfig.MCHRATE, mchRateMap);
// 默认商户最大费率
result.put(RateConfig.READONLYPARENTMCHMAX, rateConfigService.queryPaywayFeeMap(getCurrentAgentNo() + "_" + RateConfig.MCHAPPLYMAX, CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo));
return ApiRes.ok(result);
}
// 配置子服务商的费率
else if(RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode) ){
Map<String, Object> result = new HashMap<>();
Map<String, PaywayFee> agentRate = rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByAgent(infoId), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo);
// 查询已经配置的信息
result.put(RateConfig.AGENTRATE, agentRate);
AgentInfo agentInfo = agentInfoService.getById(infoId);
Map<String, PaywayFee> parentDefRate = null;
if (agentInfo.getPid() == null) {
parentDefRate = rateConfigService.queryPaywayFeeMap(infoId + "_" + RateConfig.AGENTDEF, CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo);
}
if (parentDefRate == null) {
parentDefRate = rateConfigService.queryPaywayFeeMap(isvNo + "_" + RateConfig.AGENTDEF, CS.SYS_ROLE_TYPE.ISV, ifCode, range, mccCode, isvNo);
}
Map<String, PaywayFee> mchFeeMax = rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByMchMax(infoId), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo);
Map<String, PaywayFee> isvMchFeeMax = rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByMchMax(isvNo), CS.SYS_ROLE_TYPE.ISV, ifCode, range, mccCode, isvNo);
for (Map.Entry<String, PaywayFee> isvMchFeeMaxItem : isvMchFeeMax.entrySet()) {
String wayCode = isvMchFeeMaxItem.getKey();
PaywayFee item = isvMchFeeMaxItem.getValue();
if (mchFeeMax.get(wayCode) == null) {
// 为空传递空值
mchFeeMax.put(wayCode, PaywayFee.toEmptyData(item));
}
}
result.put(RateConfig.MCHAPPLYMAX, mchFeeMax);
// 我的费率(商户上级服务商的费率)
result.put(RateConfig.READONLYPARENTAGENT, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByAgent(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo));
// 默认费率
result.put(RateConfig.READONLYPARENTDEFRATE, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByAgentDef(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo));
// 商户最大费率
result.put(RateConfig.READONLYPARENTMCHMAX, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByMchMax(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo));
PaywayFee.resetData(agentRate, baseConverter.newPaywayFeeMap(parentDefRate));
return ApiRes.ok(result);
}// 配置服务商自己的配置
else if(RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode) ){
Map<String, Object> result = new HashMap<>();
// 当前服务商的费率配置信息
result.put(RateConfig.AGENTRATE, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByAgent(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo));
// 用于显示代理的费率信息(兼容前端)
result.put(RateConfig.READONLYPARENTAGENT, result.get(RateConfig.AGENTRATE));
// 商户默认费率
result.put(RateConfig.MCHAPPLYDEF, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByMchDef(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo));
// 服务商默认费率
result.put(RateConfig.AGENTDEF, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByAgentDef(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo));
// 商户最大费率
result.put(RateConfig.READONLYPARENTMCHMAX, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByMchMax(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo));
return ApiRes.ok(result);
}
return ApiRes.ok();
}
/** 保存费率信息 **/
@MethodLog(remark = "配置费率")
@PostMapping(value="")
public ApiRes reset() {
// 需要删除的集合, 比如: 配置渠道商底价, 关闭了某些渠道, 那么需要将下属的配置删除掉。
List<RateConfig> delList = new ArrayList<>();
String configMode = getValStringRequired("configMode");
// 主对象
RateConfig mainRateConfig = getObject(RateConfig.class);
mainRateConfig.setInfoType(commonGetInfoType(configMode)); // 必须设置infoType, 检查费率会使用
// 当前服务商的配置信息
if(RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)){
mainRateConfig.setInfoId(getCurrentAgentNo());
}
List<RateConfig> list = new ArrayList<>();
// 服务商默认费率 infoId = ISVNO_AGENTDEF infoType = 1(服务商)
if(StringUtils.isNotEmpty(mainRateConfig.extv().getString(RateConfig.AGENTDEF))){
JSON.parseArray(mainRateConfig.extv().getString(RateConfig.AGENTDEF), PaywayFee.class)
.forEach(r -> list.add(getFillInfoIdAndType(mainRateConfig, r, RateConfig.AGENTDEF, configMode)));
}
// 商户默认费率 infoId = ISVNO_MCHAPPLYDEF infoType = 1(服务商)
if(StringUtils.isNotEmpty(mainRateConfig.extv().getString(RateConfig.MCHAPPLYDEF))){
JSON.parseArray(mainRateConfig.extv().getString(RateConfig.MCHAPPLYDEF), PaywayFee.class)
.forEach(r -> list.add(getFillInfoIdAndType(mainRateConfig, r, RateConfig.MCHAPPLYDEF, configMode)));
}
// 商户费率
if(StringUtils.isNotEmpty(mainRateConfig.extv().getString(RateConfig.MCHRATE))){
JSON.parseArray(mainRateConfig.extv().getString(RateConfig.MCHRATE), PaywayFee.class)
.forEach(r -> list.add(getFillInfoIdAndType(mainRateConfig, r, RateConfig.MCHRATE, configMode)));
}
// 服务商费率
if(StringUtils.isNotEmpty(mainRateConfig.extv().getString(RateConfig.AGENTRATE))){
JSON.parseArray(mainRateConfig.extv().getString(RateConfig.AGENTRATE), PaywayFee.class)
.forEach(r -> list.add(getFillInfoIdAndType(mainRateConfig, r, RateConfig.AGENTRATE, configMode)));
// 配置 服务商 需要删除 下属配置。
delList = this.genDelRateConfigList(null, mainRateConfig.getInfoId(), mainRateConfig.getIfCode());
}
// 服务商最大费率 infoId = ISVNO_AGENTMAX infoType = 1(服务商)
if (!ObjUtil.isEmpty(mainRateConfig.extv().getString(RateConfig.AGENTMAX))) {
JSON.parseArray(mainRateConfig.extv().getString(RateConfig.AGENTMAX), PaywayFee.class)
.forEach(r -> list.add( getFillInfoIdAndType(mainRateConfig, r, RateConfig.AGENTMAX, configMode)));
}
// 商户最大费率 infoId = ISVNO_MCHAPPLYMAX infoType = 1(服务商)
if (configMode.equalsIgnoreCase(RateConfig.CONFIG_MODE_AGENTSELF)
|| configMode.equalsIgnoreCase(RateConfig.CONFIG_MODE_AGENTEMCH)) {
// 配置代理费率和商户费率时,删除最大费率值
mainRateConfig.getExt().remove(RateConfig.MCHAPPLYMAX);
}
if (!ObjUtil.isEmpty(mainRateConfig.extv().getString(RateConfig.MCHAPPLYMAX))) {
JSON.parseArray(mainRateConfig.extv().getString(RateConfig.MCHAPPLYMAX), PaywayFee.class)
.forEach(r -> list.add(getFillInfoIdAndType(mainRateConfig, r, RateConfig.MCHAPPLYMAX, configMode)));
}
LambdaQueryWrapper<RateConfig> delWrapper = RateConfig.gw();
delWrapper.eq(RateConfig::getIfCode, mainRateConfig.getIfCode());
delWrapper.eq(RateConfig::getInfoType, commonGetInfoType(configMode));
delWrapper.eq(mainRateConfig.getRange()!= null, RateConfig::getRange, mainRateConfig.getRange());
delWrapper.eq(!ObjUtil.isEmpty(mainRateConfig.getMccCode()), RateConfig::getMccCode, mainRateConfig.getMccCode());
delWrapper.in(RateConfig::getInfoId, commonGetInfoId(configMode, mainRateConfig.getInfoId()));
rateConfigService.resetRate(list, delWrapper, mainRateConfig, false, delList);
return ApiRes.ok();
}
private RateConfig getFillInfoIdAndType(RateConfig mainRateConfig, PaywayFee paywayFee, String infoSuffix, String configMode){
RateConfig result = new RateConfig();
result.setInfoId(mainRateConfig.getInfoId() + "_" + infoSuffix);
result.setIfCode(mainRateConfig.getIfCode());
result.setMccCode(mainRateConfig.getMccCode());
result.setRange(mainRateConfig.getRange());
result.setIsvNo(mainRateConfig.getIsvNo());
result.setWayCode(paywayFee.getWayCode());
result.setFeeType(paywayFee.getFeeType());
result.setFeeRate(paywayFee.getFeeRate());
result.setApplymentSupport(paywayFee.getApplymentSupport());
result.setPaywayFeeDetail((JSONObject) JSON.toJSON(paywayFee));
result.setInfoType(commonGetInfoType(configMode));
return result;
}
private String commonGetInfoType(String configMode){
//设置服务商信息
if(RateConfig.CONFIG_MODE_MGRISV.equals(configMode)){
return CS.SYS_ROLE_TYPE.ISV;
}else if(RateConfig.CONFIG_MODE_MGRAGENT.equals(configMode)){
return CS.SYS_ROLE_TYPE.AGENT;
}else if(RateConfig.CONFIG_MODE_MGRMCH.equals(configMode)){
return CS.SYS_ROLE_TYPE.MCH_APP;
}else if(RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)){
return CS.SYS_ROLE_TYPE.AGENT;
}else if(RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode)){
return CS.SYS_ROLE_TYPE.AGENT;
}else if(RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode)){
return CS.SYS_ROLE_TYPE.MCH_APP;
}
return "";
}
private List<String> commonGetInfoId(String configMode, String infoId){
//设置服务商信息
if(RateConfig.CONFIG_MODE_MGRISV.equals(configMode)){
return Arrays.asList(
(infoId + "_" + RateConfig.ISVCOST),
(infoId + "_" + RateConfig.AGENTDEF),
(infoId + "_" + RateConfig.AGENTMAX),
(infoId + "_" + RateConfig.MCHAPPLYDEF),
(infoId + "_" + RateConfig.MCHAPPLYMAX)
);
}else if(RateConfig.CONFIG_MODE_MGRAGENT.equals(configMode)){
return Arrays.asList(
(infoId + "_" + RateConfig.AGENTRATE),
(infoId + "_" + RateConfig.AGENTDEF),
(infoId + "_" + RateConfig.AGENTMAX),
(infoId + "_" + RateConfig.MCHAPPLYDEF),
(infoId + "_" + RateConfig.MCHAPPLYMAX)
);
}else if(RateConfig.CONFIG_MODE_MGRMCH.equals(configMode)){
return Collections.singletonList(
(infoId + "_" + RateConfig.MCHRATE)
);
}else if(RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)){
return Arrays.asList(
(infoId + "_" + RateConfig.AGENTDEF),
(infoId + "_" + RateConfig.MCHAPPLYDEF),
(infoId + "_" + RateConfig.MCHAPPLYMAX)
);
}else if(RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode)){
return Arrays.asList(
(infoId + "_" + RateConfig.AGENTRATE),
(infoId + "_" + RateConfig.MCHAPPLYMAX)
);
}else if(RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode)){
return Collections.singletonList(
(infoId + "_" + RateConfig.MCHRATE)
);
}
return new ArrayList<>();
}
/**
获取待删除的列表集合 info_id/ info_type if_code way_code
以下三个场景需要判断:
渠道商底价
运营平台 --》 设置服务商费率
服务商 配置 下级服务商费率 (服务商)
**/
private List<RateConfig> genDelRateConfigList(String isvNo, String agentNo, String ifCode){
String delPaywayCodeListStr = getValString("delPaywayCodeListStr");
if(StringUtils.isEmpty(delPaywayCodeListStr)){
return null;
}
List<String> delWayCodeList = JSON.parseArray(delPaywayCodeListStr, String.class);
// 没有待删除的列表
if(delWayCodeList.isEmpty()){
return null;
}
List<RateConfig> result = new ArrayList<>();
Set<String> allAgentNoList = new HashSet<>();
Set<String> allMchNoList = new HashSet<>();
Set<String> allAppIdList = new HashSet<>();
// 服务商不为空
if(StringUtils.isNotEmpty(isvNo)){
// 判断是否支持服务商
if(SysConfigService.IS_HAS_AGENT_ENT){
// 查询所有的服务商列表 ( 一级服务商 )
agentInfoService.list(AgentInfo.gw().select(AgentInfo::getAgentNo).eq(AgentInfo::getIsvNo, isvNo)).forEach(r -> allAgentNoList.add(r.getAgentNo()));
}
// 查询所有的商户列表 [ 无需查询服务商的所属了, 已经是全部服务商下的商户了。 ]
mchInfoService.lambdaQuery().select(MchInfo::getMchNo).list().forEach(r -> allMchNoList.add(r.getMchNo()));
// 查询下级服务商的 子服务商【递归】
for (String agentNoItem : allAgentNoList) {
allAgentNoList.addAll(agentInfoService.queryAllSubAgentNo(agentNoItem));
}
// 查询下级服务商【递归】的商户
}
// 服务商不为空
if(StringUtils.isNotEmpty(agentNo)){
// 查询所有的服务商列表 当前服务商的 直属 服务商
agentInfoService.lambdaQuery().select(AgentInfo::getAgentNo).eq(AgentInfo::getPid, agentNo).list().forEach(r -> allAgentNoList.add(r.getAgentNo()));
// 查询所有的商户列表 当前服务商的 直属 商户 【 当前服务商的所属商户 】
mchInfoService.lambdaQuery().select(MchInfo::getMchNo).eq(MchInfo::getAgentNo, agentNo).list().forEach(r -> allMchNoList.add(r.getMchNo()));
// 查询下级服务商的 子服务商【递归】
for (String agentNoItem : allAgentNoList) {
allAgentNoList.addAll(agentInfoService.queryAllSubAgentNo(agentNoItem));
}
// 查询下级服务商 所属的商户集合
for (String agentNoItem : allAgentNoList) {
mchInfoService.lambdaQuery().select(MchInfo::getMchNo).eq(MchInfo::getAgentNo, agentNoItem)
.list().forEach(r -> allMchNoList.add(r.getMchNo()));
}
}
if(!allMchNoList.isEmpty()){
// 查询所有的商户列表
mchAppService.lambdaQuery().select(MchAppEntity::getMchNo).in(MchAppEntity::getMchNo, allMchNoList)
.list().forEach(r -> allAppIdList.add(r.getAppId()));
}
// 服务商: 包括 服务商配置, 下级服务商默认、 服务商商户默认
for (String agentNoItem : allAgentNoList) {
for (String wayCode : delWayCodeList) {
RateConfig r = new RateConfig();
r.setInfoId(RateConfig.buildInfoId(agentNoItem, RateConfig.AGENTRATE)); r.setInfoType(CS.SYS_ROLE_TYPE.AGENT); r.setIfCode(ifCode); r.setWayCode(wayCode);
result.add(r);
RateConfig r1 = new RateConfig();
r1.setInfoId(RateConfig.buildInfoId(agentNoItem, RateConfig.AGENTDEF)); r1.setInfoType(CS.SYS_ROLE_TYPE.AGENT); r1.setIfCode(ifCode); r1.setWayCode(wayCode);
result.add(r1);
RateConfig r2 = new RateConfig();
r2.setInfoId(RateConfig.buildInfoId(agentNoItem, RateConfig.MCHAPPLYDEF)); r2.setInfoType(CS.SYS_ROLE_TYPE.AGENT); r2.setIfCode(ifCode); r2.setWayCode(wayCode);
result.add(r2);
}
}
// 商户: 包括 商户应用费率
for (String appIdItem : allAppIdList) {
for (String wayCode : delWayCodeList) {
RateConfig r = new RateConfig();
r.setInfoId(RateConfig.buildInfoId(appIdItem, RateConfig.MCHRATE)); r.setInfoType(CS.SYS_ROLE_TYPE.MCH_APP); r.setIfCode(ifCode); r.setWayCode(wayCode);
result.add(r);
}
}
return result;
}
@GetMapping("/rateInfoDetail")
public ApiRes rateInfoDetail() {
String isvNo = getValStringRequired("isvNo");
String ifCode = getValStringRequired("ifCode");
Integer range = getValInteger("range");
String mccCode = getValString("mccCode");
String infoType = getValStringRequired("infoType");
String infoId = getValStringRequired("infoId");
String currentAgentNo = getCurrentAgentNo();
List<RateConfigSimple> result = rateConfigV2Service.getRankFeeList(isvNo, infoType, infoId, ifCode, range, mccCode, currentAgentNo);
return ApiRes.ok(result);
}
@PostMapping("/resetV2")
public ApiRes resetV2() {
String currentAgentNo = getCurrentAgentNo();
RateConfigSimple rateConfigSimple = getObject(RateConfigSimple.class);
if (rateConfigSimple.getInfoType().equalsIgnoreCase(CS.SYS_ROLE_TYPE.AGENT)) {
AgentInfo agentInfo = agentInfoService.getById(rateConfigSimple.getInfoId());
Assert.equals(agentInfo.getPid(), currentAgentNo, "所操作的服务商与登录账号非上下级关系");
} else if (rateConfigSimple.getInfoType().equalsIgnoreCase(CS.SYS_ROLE_TYPE.MCH)) {
MchInfo mchInfo = mchInfoService.getById(rateConfigSimple.getInfoId());
Assert.equals(mchInfo.getAgentNo(), currentAgentNo, "所操作的用户与登录账号非上下级关系");
} else {
throw new BizException("未知的操作类型");
}
rateConfigV2Service.save(rateConfigSimple);
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,148 @@
package com.jeequan.jeepay.agent.ctrl.product;
import cn.hutool.core.util.ObjUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.PackageOrder;
import com.jeequan.jeepay.db.entity.ProductInfo;
import com.jeequan.jeepay.db.entity.ProductType;
import com.jeequan.jeepay.service.impl.ProductAppService;
import com.jeequan.jeepay.service.impl.ProductInfoService;
import com.jeequan.jeepay.service.impl.ProductTypeService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
* 产品中心
*
* @author deng
* @since 2024-04-10
*/
@RestController
@RequestMapping("/api/product")
public class ProductController extends CommonCtrl {
@Autowired
private ProductInfoService productInfoService;
@Autowired
private ProductTypeService productTypeService;
@Autowired
private ProductAppService productAppService;
/**
* 产品中心列表
**/
@RequestMapping(value = "/getProductList", method = RequestMethod.GET)
@MethodLog(remark = "产品中心列表")
public ApiRes getProductList() throws BizException {
ProductInfo productInfo = getObject(ProductInfo.class);
/*LambdaQueryWrapper<ProductInfo> wrapper = ProductInfo.gw();
selectParams(productInfo, wrapper);
wrapper.orderByDesc(ProductInfo::getCreatedAt);*/
Page<ProductInfo> page = new Page<>();
List<ProductInfo> productInfoList = productInfoService.getProductList(productInfo.getProductName(), productInfo.getState(), productInfo.getProductType());
page.setRecords(productInfoList);
page.setTotal(productInfoList.size());
page.setCurrent(1);
return ApiRes.ok(page);
}
@RequestMapping(value = "/getProductById", method = RequestMethod.GET)
@MethodLog(remark = "产品详情")
public ApiRes getProductById() throws BizException {
//获取查询条件
ProductInfo productInfo = getObject(ProductInfo.class);
ProductInfo info = productInfoService.getProductById(productInfo.getProductId());
return ApiRes.ok(info);
}
@RequestMapping(value = "/getProductByUser", method = RequestMethod.GET)
@MethodLog(remark = "被选择用户绑定关系")
public ApiRes getProductByUser() throws BizException {
//获取查询条件
String productOrPackage = getValStringRequired("productOrPackage");
String userNo = getValStringRequired("userNo");
ProductInfo resut=new ProductInfo();
//查询已关联已开通的应用数量,
List<PackageOrder> packageOrderList = productAppService.getList(productOrPackage,userNo);
List<String> bindingApp = packageOrderList.stream().map(PackageOrder::getAppId).filter(str-> !str.isEmpty()).distinct().collect(Collectors.toList());
resut.setApplyCount(packageOrderList.size());
resut.setBindingAppList(bindingApp);
//返回收费信息和剩余天数以及总剩余天数
List<PackageOrder> packageOrderListSave =new ArrayList<>();
long allRemainingDays = 0L;
for (PackageOrder packageOrder : packageOrderList) {
if (packageOrder.getCostRule() != null){
JSONArray costRule = packageOrder.getCostRule();
//目前规则只能选取一条
int validTime = costRule.getJSONObject(0).getIntValue("validTime");
if (costRule.getJSONObject(0).getDate("autoTime") != null){
LocalDate currentDate = costRule.getJSONObject(0).getDate("autoTime").toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
// 计算到期后的日期
LocalDate futureDate = currentDate.plusDays(validTime);
// 计算剩余天数
LocalDate today = new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
long remainingDays = ChronoUnit.DAYS.between(today, futureDate);
packageOrder.setRemainingDays(remainingDays);
//暂时不需要
//productAppListSave.add(productApp);
allRemainingDays += remainingDays;
}
}
}
//暂时不需要
//info.setProductAppList(productAppListSave);
resut.setAllRemainingDays(allRemainingDays);
return ApiRes.ok(resut);
}
@RequestMapping(value = "/startProduct", method = RequestMethod.POST)
@MethodLog(remark = "产品开通")
public ApiRes startProduct() throws BizException {
//获取查询条件
PackageOrder app = getObject(PackageOrder.class);
Assert.isTrue(!ObjUtil.isEmpty(getValString("userNo")), "用户号[userNo]不能为空");
app.setMchNo(getValString("userNo"));
app.setCreatedAt(new Date());
app.setUpdatedAt(new Date());
app.setCreatedUid(getCurrentUser().getSysUserId());
productInfoService.startProduct(app);
return ApiRes.ok("已提交!");
}
@RequestMapping(value = "/getProductTypeList", method = RequestMethod.GET)
@MethodLog(remark = "获取所有分类列表")
public ApiRes getProductTypeList() throws BizException {
return ApiRes.ok(productTypeService.list(ProductType.gw()));
}
/**
* @author: huay
* @describe: 查询公共条件
*/
public void selectParams(ProductInfo productInfo, LambdaQueryWrapper<ProductInfo> wrapper) {
wrapper.like(StringUtils.isNotEmpty(productInfo.getProductName()), ProductInfo::getProductName, productInfo.getProductName());
wrapper.eq(ProductInfo::getState, productInfo.getState());
}
}

View File

@@ -0,0 +1,482 @@
package com.jeequan.jeepay.agent.ctrl.qrcode;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.bizcommons.manage.qrshell.AbstractGenerator;
import com.jeequan.jeepay.bizcommons.manage.qrshell.ShellQRGenerator;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.DBApplicationConfig;
import com.jeequan.jeepay.core.model.QRCodeParams;
import com.jeequan.jeepay.core.model.export.MchQrCodesExportExcel;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.core.utils.ExcelUtil;
import com.jeequan.jeepay.core.utils.JeepayKit;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.service.impl.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 商户应用管理类
*
* @author zhuxiao
* @date 2021-06-16 09:15
*/
@RestController
@RequestMapping("/api/mchQrCodes")
public class MchQrCodeController extends CommonCtrl {
@Autowired private MchQrcodeCardService mchQrcodeCardService;
@Autowired private MchQrcShellService mchQrcShellService;
@Autowired private MchInfoService mchInfoService;
@Autowired private MchStoreService mchStoreService;
@Autowired private MchAppService mchAppService;
@Autowired private MchApplymentService mchApplymentService;
@PreAuthorize("hasAuthority('ENT_DEVICE_QRC_LIST')")
@GetMapping
public ApiRes list() {
// 构造查询条件
MchQrcodeCard mchQrCode = getObject(MchQrcodeCard.class);
// 可查看自己和全部下级代理的设备
String currentAgentNo = getCurrentAgentNo();
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
// 自己和下级服务商
if (CollUtil.isNotEmpty(subAgentNoList)){
mchQrCode.setSubAgentNoList(subAgentNoList);
}
IPage<MchQrcodeCard> page = mchQrcodeCardService.selectPageRecords(getIPage(), mchQrCode);
if (page.getTotal() == 0) {
return ApiRes.page(page);
}
// 列表添加是否属于自身设备只能绑定直属商户app端展示隐藏也使用此字段
for (MchQrcodeCard qrcodeCard: page.getRecords()) {
if (currentAgentNo.equals(qrcodeCard.getAgentNo())) {
qrcodeCard.addExt("isSelf", true);
}
}
return ApiRes.page(page);
}
@PreAuthorize("hasAuthority('ENT_DEVICE_QRC_VIEW')")
@GetMapping("/{recordId}")
public ApiRes detail(@PathVariable("recordId") Long recordId) {
// 可查看自己和全部下级代理的码牌
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
MchQrcodeCard dbRecord = mchQrcodeCardService.getById(recordId);
if (!subAgentNoList.contains(dbRecord.getAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
// 设备是否属于自身
if (getCurrentAgentNo().equals(dbRecord.getAgentNo())) {
dbRecord.addExt("isSelf", true);
}
// 添加服务商、商户、门店、应用名称
AgentInfo allotAgent = agentInfoService.getById(dbRecord.getAgentNo());
if (allotAgent != null) {
dbRecord.addExt("agentName", allotAgent.getAgentName());
}
if (dbRecord.getBindState() == CS.YES) {
if (StringUtils.isNotBlank(dbRecord.getMchNo())) {
MchInfo mchInfo = mchInfoService.getById(dbRecord.getMchNo());
if (mchInfo != null) {
dbRecord.addExt("mchName", mchInfo.getMchName());
}
}
if (dbRecord.getStoreId() != null) {
MchStore mchStore = mchStoreService.getById(dbRecord.getStoreId());
if (mchStore != null) {
dbRecord.addExt("storeName", mchStore.getStoreName());
}
}
if (StringUtils.isNotBlank(dbRecord.getAppId())) {
MchAppEntity mchAppEntity = mchAppService.getById(dbRecord.getAppId());
if (mchAppEntity != null) {
dbRecord.addExt("appName", mchAppEntity.getAppName());
}
}
}
MchApplyment mchApplyment = mchApplymentService.getById(dbRecord.getMchApplyId());
// 封装URL
dbRecord.addExt("qrUrl", sysConfigService.getDBApplicationConfig().genUniJsapiPayUrl(QRCodeParams.TYPE_QRC, dbRecord.getEntryPage(), recordId + "", mchApplyment.getIsvNo()));
return ApiRes.ok(dbRecord);
}
@PreAuthorize("hasAuthority('ENT_DEVICE_QRC_EDIT')")
@MethodLog(remark = "更新二维码信息")
@PutMapping("/{recordId}")
public ApiRes update(@PathVariable("recordId") Long recordId) {
// 可查看自己和全部下级代理的码牌
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
MchQrcodeCard dbRecord = mchQrcodeCardService.getById(recordId);
if (!subAgentNoList.contains(dbRecord.getAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
// 处理金额类型
handleParamAmount("fixedPayAmount");
MchQrcodeCard mchQrCode = getObject(MchQrcodeCard.class);
mchQrCode.setBatchId(null); // 批次号不允许变更
mchQrCode.setCreatedAt(null);
mchQrCode.setUpdatedAt(null);
mchQrCode.setQrcId(recordId);
// 解绑同时设置商户号为空串设置门店ID为-1
if (mchQrCode.getBindState() != null && mchQrCode.getBindState() == CS.NO) {
mchQrCode.setMchNo("");
mchQrCode.setAppId("");
mchQrCode.setStoreId("-1");
}
boolean result = mchQrcodeCardService.updateById(mchQrCode);
if (!result) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
}
return ApiRes.ok();
}
/** 解析二维码 && 验证二维码是否可绑定 **/
@GetMapping("/parseQrCodeUrl")
public ApiRes parseQrCodeUrl() {
String url = getValStringRequired("qrUrl");
// 不是支付平台开头的, 说明不是可用二维码
if(!url.startsWith(sysConfigService.getDBApplicationConfig().getPaySiteUrl())){
throw new BizException("二维码解析失败");
}
int tokenIndex = url.indexOf(JeepayKit.TOKEN_KEY + "=");
if(tokenIndex <= 0){
throw new BizException("二维码解析失败");
}
String token = url.substring(tokenIndex + 12);
QRCodeParams qrCodeParams = JSON.parseObject(JeepayKit.aesDecode(token), QRCodeParams.class); //解析token
MchQrcodeCard mchQrcodeCard = mchQrcodeCardService.getById( qrCodeParams.getId());
// 不存在 不可用 已绑定
if(mchQrcodeCard == null || mchQrcodeCard.getQrcState() != CS.YES || mchQrcodeCard.getBindState() != CS.NO){
throw new BizException("二维码不存在");
}
return ApiRes.ok(mchQrcodeCard.getQrcId());
}
/**
* @author: xiaoyu
* @date: 2022/1/14 9:45
* @describe: 订单列表数据导出
*/
@PreAuthorize("hasAuthority('ENT_DEVICE_QRC_EXPORT')")
@RequestMapping(value="/exportExcel", method = RequestMethod.GET)
public void exportExcel() throws Exception{
String exportModel = getValStringRequired("exportModel");
MchQrcodeCard mchQrcodeCard = getObject(MchQrcodeCard.class);
LambdaQueryWrapper<MchQrcodeCard> wrapper = MchQrcodeCard.gw();
if(mchQrcodeCardService.countByWrapper(mchQrcodeCard) > 500){
throw new BizException("导出数量不可超过500");
}
// 服务商号条件不为空,搜索该服务商号下
wrapper.eq(StringUtils.isNotEmpty(mchQrcodeCard.getAgentNo()), MchQrcodeCard::getAgentNo, mchQrcodeCard.getAgentNo());
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
// 自己和下级服务商
wrapper.in(CollUtil.isNotEmpty(subAgentNoList), MchQrcodeCard::getAgentNo, subAgentNoList);
IPage<MchQrcodeCard> pages = mchQrcodeCardService.listByPage(getIPage(true), mchQrcodeCard, wrapper);
// 查询当前系统配置信息
DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig();
// Excel: 信息和url
if ("infoAndUrl".equals(exportModel)) {
try {
List<JSONObject> newList = new LinkedList<>();
for (MchQrcodeCard qrcodeCard:pages.getRecords()) {
MchApplyment mchApplyment = mchApplymentService.getById(qrcodeCard.getMchApplyId());
JSONObject object = (JSONObject) JSONObject.toJSON(qrcodeCard);
object.put("fixedPayAmount", AmountUtil.convertCent2Dollar(qrcodeCard.getFixedPayAmount()));
object.put("qrCodeUrl", dbApplicationConfig.genUniJsapiPayUrl(QRCodeParams.TYPE_QRC, qrcodeCard.getEntryPage(), qrcodeCard.getQrcId() + "", mchApplyment.getIsvNo()));
newList.add(object);
}
List<MchQrCodesExportExcel> linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), MchQrCodesExportExcel.class);
// excel输出
ExcelUtil.exportExcel(linkedList, "码牌", "码牌", MchQrCodesExportExcel.class, "码牌", response);
}catch (Exception e) {
logger.error("导出excel失败", e);
throw new BizException("导出二维码失败!");
}
// 模板图片 || 纯二维码 || 二维码包含ID
}else if ("templateImg".equals(exportModel) || "qrcode".equals(exportModel) || "qrcodeAndQrcId".equals(exportModel) ) {
//文件的名称
String downloadFilename = "qrcode_" + DateUtil.today() + ".zip";
//设置格式
response.setCharacterEncoding("UTF-8");
response.setHeader("content-Type", "application/x-msdownload");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(downloadFilename, "UTF-8"));
ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
// 查询所有的模板数据
Map<Long, MchQrcShell> map = new HashMap<>();
pages.getRecords().stream().forEach(r -> map.put(r.getQrcShellId(), null));
if(!map.keySet().isEmpty()){
mchQrcShellService.list(MchQrcShell.gw().in(MchQrcShell::getSid, map.keySet())).stream().forEach(r -> {
map.put(r.getSid(), r);
});
}
for (MchQrcodeCard qrcodeCard:pages.getRecords()) {
String mchStoreName = "";
if(qrcodeCard.getBindState() == CS.YES && qrcodeCard.getStoreId() != null && !"-1".equals(qrcodeCard.getStoreId())){
MchStore mchStore = mchStoreService.getById(qrcodeCard.getStoreId());
mchStoreName = mchStore != null ? mchStore.getStoreName() : "";
}
BufferedImage bufferedImage = null;
MchQrcShell mchQrcShell = map.get(qrcodeCard.getQrcShellId());
AbstractGenerator abstractGenerator = SpringBeansUtil.getBean(ShellQRGenerator.class);
if(mchQrcShell != null && "templateImg".equals(exportModel)){ //存在模板 && 显式导出模板
abstractGenerator = getAbstractGenerator(mchQrcShell.getStyleCode());
}
String configStr = null;
if("templateImg".equals(exportModel)){ // 模板图片
if(mchQrcShell != null){
configStr = mchQrcShell.getConfigInfo();
}
}else if("qrcode".equals(exportModel)){ // 纯二维码不包含ID
configStr = "{showIdFlag: false}";
}else if("qrcodeAndQrcId".equals(exportModel)){ // 二维码 + ID
configStr = "{showIdFlag: true}";
}
MchApplyment applyment = mchApplymentService.getById(qrcodeCard.getMchApplyId());
bufferedImage = abstractGenerator
.genQrImgBuffer(configStr,
dbApplicationConfig.genUniJsapiPayUrl(QRCodeParams.TYPE_QRC, qrcodeCard.getEntryPage(), qrcodeCard.getQrcId() + "", applyment.getIsvNo()),
qrcodeCard.getQrcId(),
mchStoreName,
false
);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", out);
InputStream is = new ByteArrayInputStream(out.toByteArray());
zos.putNextEntry(new ZipEntry( qrcodeCard.getQrcId() + ".png"));
byte[] buffer = new byte[1024];
int r = 0;
while ((r = is.read(buffer)) != -1) {
zos.write(buffer, 0, r);
}
is.close();
is = null;
out.close();
out = null;
zos.flush();
}
zos.flush();
zos.close();
}
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 绑定码牌
*/
@MethodLog(remark = "绑定码牌")
@PreAuthorize("hasAuthority('ENT_DEVICE_QRC_EDIT')")
@PutMapping("/bind/{recordId}")
public ApiRes bind(@PathVariable("recordId") Long recordId) {
String mchNo = getValStringRequired("mchNo");
String appId = getValStringRequired("appId");
String storeId = getValStringRequired("storeId");
MchInfo mchInfo = mchInfoService.getById(mchNo);
if (mchInfo == null || StringUtils.isBlank(mchInfo.getAgentNo()) || !mchInfo.getAgentNo().equals(getCurrentAgentNo())) {
throw new BizException("商户不存在");
}
MchQrcodeCard dbRecord = mchQrcodeCardService.getById(recordId);
if (dbRecord == null || StringUtils.isBlank(dbRecord.getAgentNo()) || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
MchQrcodeCard updateRecord = new MchQrcodeCard();
updateRecord.setQrcId(recordId).setMchNo(mchNo).setStoreId(storeId).setAppId(appId).setBindState(CS.YES);
mchQrcodeCardService.bindEmptyQR(updateRecord);
return ApiRes.ok();
}
/**
* @Author: zx
* @Description: 解绑码牌
* @Date: 15:59 2022/5/30
*/
@MethodLog(remark = "解绑码牌")
@PreAuthorize("hasAuthority('ENT_DEVICE_QRC_RELIEVE')")
@PostMapping("/unbind/{qrcId}")
public ApiRes unbind(@PathVariable("qrcId") Long qrcId) {
MchQrcodeCard dbRecord = mchQrcodeCardService.getById(qrcId);
if (dbRecord == null || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) {
return ApiRes.customFail("解绑失败");
}
mchQrcodeCardService.unbind(dbRecord);
return ApiRes.ok();
}
/**
* @Author: zx
* @Description: 查看码牌绑定的设备列表
* @Date: 15:59 2022/5/30
*/
@PreAuthorize("hasAuthority('ENT_DEVICE_QRC_EDIT')")
@GetMapping("/bindDevice/{qrcId}")
public ApiRes bindDevice(@PathVariable("qrcId") Long qrcId) {
MchQrcodeCard dbRecord = mchQrcodeCardService.getById(qrcId);
if (dbRecord == null || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
IPage<MchStoreDevice> page = mchQrcodeCardService.getBindDevice(getIPage(), dbRecord, getCurrentAgentNo());
return ApiRes.page(page);
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 划拨码牌给服务商
*/
@MethodLog(remark = "划拨/收回码牌给服务商")
@PreAuthorize("hasAuthority('ENT_DEVICE_QRC_ALLOT')")
@PostMapping("/allotQrc")
public ApiRes allotQrc() {
// 服务商是否支持划拨码牌、设备
SysConfig isSupportAgentAllot = sysConfigService.getById("isSupportAgentAllot");
if(isSupportAgentAllot == null || String.valueOf(CS.NO).equals(isSupportAgentAllot.getConfigVal())){
throw new BizException("不支持服务商划拨码牌、设备");
}
String allotType = getValStringRequired("allotType"); // 划拨类型select-勾选划拨 batch-批次划拨
String allotOrRecover = getValStringRequired("allotOrRecover"); // 分配类型allot-划拨 recover-收回
List<Long> qrcIdList = new LinkedList<>();
// 构建批量更新设备ID集合
if (allotType.equals("select")) {
String allotds = getValStringRequired("allotIds");
qrcIdList = Arrays.stream(allotds.split(",")).map(Long::parseLong).collect(Collectors.toList());
}else if (allotType.equals("batch")) {
String batchId = getValStringRequired("batchId");
List<MchQrcodeCard> list = mchQrcodeCardService.list(MchQrcodeCard.gw().eq(MchQrcodeCard::getBatchId, batchId));
if (CollUtil.isEmpty(list)) {
throw new BizException("批次号错误");
}
for (MchQrcodeCard mchQrcodeCard : list) {
qrcIdList.add(mchQrcodeCard.getQrcId());
}
}else {
throw new BizException("划拨类型错误");
}
if (CollUtil.isEmpty(qrcIdList)) {
throw new BizException("请选择码牌");
}
// 只能操作下级代理
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
// 1、收回码牌
if (allotOrRecover.equals("recover")) {
mchQrcodeCardService.recoverQrc(true, qrcIdList, subAgentNoList, getCurrentAgentNo());
return ApiRes.ok();
}
// 2、划拨码牌
String agentNo = getValStringRequired("agentNo");
List<String> mchNoList = getMchNoListByAgentNo(agentNo);
mchQrcodeCardService.allotQrc(true, agentNo, qrcIdList, mchNoList, subAgentNoList);
return ApiRes.ok();
}
private AbstractGenerator getAbstractGenerator(String code){
AbstractGenerator generator = SpringBeansUtil.getBean(code + "Generator", AbstractGenerator.class);
if(generator == null){
throw new BizException("选择模板[" + code + "]不存在!");
}
return generator;
}
}

View File

@@ -0,0 +1,85 @@
package com.jeequan.jeepay.agent.ctrl.qrcode;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.bizcommons.manage.qrshell.AbstractGenerator;
import com.jeequan.jeepay.bizcommons.manage.qrshell.ShellQRGenerator;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.QRCodeParams;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.db.entity.MchApplyment;
import com.jeequan.jeepay.db.entity.MchQrcShell;
import com.jeequan.jeepay.db.entity.MchQrcodeCard;
import com.jeequan.jeepay.db.entity.MchStore;
import com.jeequan.jeepay.service.impl.MchApplymentService;
import com.jeequan.jeepay.service.impl.MchQrcShellService;
import com.jeequan.jeepay.service.impl.MchQrcodeCardService;
import com.jeequan.jeepay.service.impl.SysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.awt.image.BufferedImage;
/**
* 二维码模板管理
*
* @author terrfly
* @date 2022/1/17 14:22
*/
@RestController
@RequestMapping("/api/mchQrcShells")
public class MchQrcShellController extends CommonCtrl {
@Autowired private MchQrcodeCardService mchQrcodeCardService;
@Autowired private MchQrcShellService mchQrcShellService;
@Autowired private SysConfigService sysConfigService;
@Autowired private MchApplymentService mchApplymentService;
/** 根据qrcId获取图片base64 **/
@GetMapping("/viewByQrc/{qrcId}")
public ApiRes viewByQrc(@PathVariable("qrcId") Long qrcId) throws Exception {
MchQrcodeCard dbRecord = mchQrcodeCardService.getById(qrcId);
String mchStoreName = "";
if(dbRecord.getBindState() == CS.YES && dbRecord.getStoreId() != null && !"-1".equals(dbRecord.getStoreId())){
MchStore mchStore = mchStoreService.getById(dbRecord.getStoreId());
mchStoreName = mchStore != null ? mchStore.getStoreName() : "";
}
AbstractGenerator shellGenerator = SpringBeansUtil.getBean(ShellQRGenerator.class);
MchApplyment applyment = mchApplymentService.getById(dbRecord.getMchApplyId());
// 封装URL
String qrUrlContent = sysConfigService.getDBApplicationConfig().genUniJsapiPayUrl(QRCodeParams.TYPE_QRC, dbRecord.getEntryPage(), qrcId + "", applyment.getIsvNo());
if(dbRecord.getQrcShellId() == null || dbRecord.getQrcShellId() <= 0){
//给前端拼接上 【 data:image/jpg;base64 】
return ApiRes.ok("data:image/jpg;base64,"+ AbstractGenerator.convertImgBase64(shellGenerator.genQrImgBuffer(null, qrUrlContent, qrcId, mchStoreName, false)));
}
MchQrcShell mchQrcShell = mchQrcShellService.getById(dbRecord.getQrcShellId());
BufferedImage bufferedImage = getAbstractGenerator(mchQrcShell.getStyleCode()).genQrImgBuffer(mchQrcShell.getConfigInfo(), qrUrlContent, qrcId, mchStoreName, false);
//给前端拼接上 【 data:image/jpg;base64 】
return ApiRes.ok("data:image/jpg;base64,"+ AbstractGenerator.convertImgBase64(bufferedImage));
}
private AbstractGenerator getAbstractGenerator(String code){
AbstractGenerator generator = SpringBeansUtil.getBean(code + "Generator", AbstractGenerator.class);
if(generator == null){
throw new BizException("选择模板[" + code + "]不存在!");
}
return generator;
}
}

View File

@@ -0,0 +1,130 @@
package com.jeequan.jeepay.agent.ctrl.settle;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.export.SettleInfoExportExcel;
import com.jeequan.jeepay.core.utils.ExcelUtil;
import com.jeequan.jeepay.db.entity.PayInterfaceDefine;
import com.jeequan.jeepay.db.entity.SettleInfo;
import com.jeequan.jeepay.service.impl.PayInterfaceDefineService;
import com.jeequan.jeepay.service.impl.SettleInfoService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
/**
* TODO
*
* @author crystal
* @date 2023/12/6 15:11
*/
@RestController
@RequestMapping("/api/settle")
public class SettleInfoController extends CommonCtrl {
@Autowired private SettleInfoService settleInfoService;
@Autowired private PayInterfaceDefineService payInterfaceDefineService;
@PreAuthorize("hasAuthority('ENT_SETTLE_LIST')")
@GetMapping
public ApiRes list() {
SettleInfo info = getObject(SettleInfo.class);
JSONObject paramJSON = getReqParamJSON();
LambdaQueryWrapper<SettleInfo> wrapper = SettleInfo.gw();
// 查询下级服务商
String currentAgentNo = getCurrentAgentNo();
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
wrapper.in(SettleInfo::getAgentNo,subAgentNoList);
//wrapper.eq(SettleInfo::getAgentNo, getCurrentAgentNo());
Page<SettleInfo> pages = settleInfoService.pageList(getIPage(), wrapper,info,paramJSON);
Map<String, String> ifCodeMap = new HashMap<>();
List<PayInterfaceDefine> list = payInterfaceDefineService.list();
if(!list.isEmpty()){
for (PayInterfaceDefine define:list) {
ifCodeMap.put(define.getIfCode(), define.getIfName());
}
}
for (SettleInfo data:pages.getRecords()) {
if(StringUtils.isNotBlank(data.getIfCode())){
data.setIfName(ifCodeMap.get(data.getIfCode()));
}
}
return ApiRes.page(pages);
}
/**
* 结算信息导出
*/
@RequestMapping(value="/exportExcel", method = RequestMethod.GET)
public void exportExcel() {
try {
SettleInfo info = getObject(SettleInfo.class);
JSONObject paramJSON = getReqParamJSON();
LambdaQueryWrapper<SettleInfo> wrapper = SettleInfo.gw(info);
wrapper.eq(SettleInfo::getAgentNo, getCurrentAgentNo());
Page<SettleInfo> pages = settleInfoService.pageList(getIPage(), wrapper,info,paramJSON);
Map<String, String> ifCodeMap = new HashMap<>();
List<PayInterfaceDefine> list = payInterfaceDefineService.list();
if(!list.isEmpty()){
for (PayInterfaceDefine define:list) {
ifCodeMap.put(define.getIfCode(), define.getIfName());
}
}
List<JSONObject> newList = new LinkedList<>();
if (!pages.getRecords().isEmpty()){
//成功交易总笔数
List<SettleInfo> infoList = pages.getRecords().stream().filter(p -> p.getState() == 2).collect(Collectors.toList());
//成功交易总金额
BigDecimal allSuccessAmount = BigDecimal.ZERO;
for (SettleInfo settleInfo : infoList) {
allSuccessAmount=allSuccessAmount.add(BigDecimal.valueOf(settleInfo.getSettleAmt()));
}
for (SettleInfo data:pages.getRecords()) {
if(StringUtils.isNotBlank(data.getIfCode())){
data.setIfName(ifCodeMap.get(data.getIfCode()));
}
JSONObject object = (JSONObject) JSONObject.toJSON(data);
newList.add(object);
}
}
List<SettleInfoExportExcel> linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), SettleInfoExportExcel.class);
// excel输出
ExcelUtil.exportExcel(linkedList, "结算信息", "结算信息", SettleInfoExportExcel.class, "结算信息", response);
}catch (Exception e){
logger.error("导出excel失败", e);
throw new BizException("导出结算信息失败!");
}
}
@GetMapping("/count")
public ApiRes getCount(){
SettleInfo info = getObject(SettleInfo.class);
LambdaQueryWrapper<SettleInfo> wrapper = SettleInfo.gw();
// 时间范围条件
Date[] dateRange = info.buildQueryDateRange();
if (dateRange[0] != null) {
wrapper.ge(SettleInfo::getUpdatedAt, dateRange[0]);
}
if (dateRange[1] != null) {
wrapper.le(SettleInfo::getUpdatedAt, dateRange[1]);
}
wrapper.eq(SettleInfo::getAgentNo, getCurrentAgentNo());
List<SettleInfo> infoList = settleInfoService.list(wrapper);
return settleInfoService.getCount(infoList);
}
}

View File

@@ -0,0 +1,175 @@
package com.jeequan.jeepay.agent.ctrl.statistics;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.PayOrderCount;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.export.statistic.*;
import com.jeequan.jeepay.core.utils.ExcelUtil;
import com.jeequan.jeepay.db.entity.PayOrder;
import com.jeequan.jeepay.service.impl.AgentInfoService;
import com.jeequan.jeepay.service.impl.StatsDeviceService;
import com.jeequan.jeepay.service.impl.StatsPayWayService;
import com.jeequan.jeepay.service.impl.StatsTradeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.List;
/**
* 统计列表接口
*
* @author xiaoyu
*
* @date 2022/5/23 16:52
*/
@Slf4j
@RestController
@RequestMapping("/api/statistic/export")
public class ExportExcelStatisticController extends CommonCtrl {
@Autowired private AgentInfoService agentInfoService;
@Autowired private StatsTradeService statsTradeService;
@Autowired private StatsPayWayService statsPayWayService;
@Autowired private StatsDeviceService statsDeviceService;
/**
* @author: xiaoyu
* @date: 2022/5/23 17:15
* @describe: 统计列表
*/
@PreAuthorize("hasAnyAuthority('ENT_STATISTIC_TRANSACTION', 'ENT_STATISTIC_MCH', 'ENT_STATISTIC_MCH_STORE', 'ENT_STATISTIC_MCH_WAY', 'ENT_STATISTIC_MCH_TYPE', 'ENT_STATISTIC_AGENT', 'ENT_STATISTIC_CHANNEL')")
@RequestMapping(value="", method = RequestMethod.GET)
public void list() {
JSONObject paramJSON = getReqParamJSON();
PayOrder payOrder = getObject(PayOrder.class);
List<String> agentSubList = null;
if (StringUtils.isEmpty(payOrder.getAgentNo())) {
// 查询服务商所有下级
agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
}
String method = getValStringRequired("method");
String mchNo = null;
Page<PayOrderCount> countPage = null;
switch (method) {
case CS.STATISTIC_TYPE.MCH:
// 商户
countPage = statsTradeService.selectMchStatsList(paramJSON, agentSubList);
exportExcel(countPage, StatisticMchExportExcel.class, "商户统计");
break;
case CS.STATISTIC_TYPE.AGENT:
// 服务商
countPage = statsTradeService.selectAgentStatsList(paramJSON, agentSubList);
exportExcel(countPage, StatisticAgentExportExcel.class, "服务商统计");
break;
case CS.STATISTIC_TYPE.TRANSACTION:
// 交易报表
// mapPage = payOrderService.countListByTransaction(payOrder, paramJSON, agentSubList);
countPage = statsTradeService.selectTransactionStatsList(payOrder, paramJSON, agentSubList);
exportExcel(countPage, StatisticTransactionExportExcel.class, "交易报表");
break;
case CS.STATISTIC_TYPE.STORE:
// 门店
getValStringRequired("mchNo");
countPage = statsTradeService.selectStoreStatsList(paramJSON);
exportExcel(countPage, StatisticStoreExportExcel.class, "门店统计");
break;
case CS.STATISTIC_TYPE.WAY_CODE:
// 支付方式
getValStringRequired("mchNo");
countPage = statsPayWayService.selectPayWayStatsList(paramJSON);
exportExcel(countPage, StatisticWayCodeExportExcel.class, "支付方式统计");
break;
case CS.STATISTIC_TYPE.WAY_CODE_TYPE:
// 支付类型
getValStringRequired("mchNo");
countPage = statsPayWayService.selectWayCodeTypeStatsList(paramJSON);
exportExcel(countPage, StatisticWayCodeTypeExportExcel.class, "支付类型统计");
break;
case CS.STATISTIC_TYPE.DEVICE:
// 设备统计
countPage = statsDeviceService.selectStatsList(paramJSON, agentSubList);
exportExcel(countPage, StatisticDeviceExportExcel.class, "设备统计");
break;
default:
break;
}
}
public List<String> getAgentSubList(JSONObject paramJSON, PayOrder payOrder) {
List<String> allAgentNoList = null;
if (StringUtils.isNotEmpty(payOrder.getAgentNo())) {
Boolean onlyOne = paramJSON.getBoolean("onlyOne");
// if (onlyOne) {
// // 仅查询单个服务商
// allAgentNoList = Arrays.asList(payOrder.getAgentNo());
// } else if ("onlyOne".equals(payOrder.getAgentNo())) {
// allAgentNoList = Arrays.asList(getCurrentAgentNo());
// } else {
// // 查询服务商所有下级
// allAgentNoList = agentInfoService.queryAllSubAgentNo(payOrder.getAgentNo());
// }
}
return allAgentNoList;
}
/** 通用导出类 **/
public void exportExcel(Page<PayOrderCount> countPage, Class clazz, String title) {
try {
List<JSONObject> newList = new LinkedList<>();
countPage.getRecords().stream().forEach(record -> {
JSONObject itemData = (JSONObject) JSONObject.toJSON(record);
// 交易金额转换
BigDecimal totalSuccAmt = new BigDecimal(record.getTotalSuccAmt()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
itemData.put("allAmount", totalSuccAmt);
// 实收金额转换
BigDecimal totalFinalAmt = BigDecimal.valueOf(record.getTotalFinalAmt()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
itemData.put("payAmount", totalFinalAmt);
// 退款金额转换
BigDecimal refundAmount = BigDecimal.valueOf(record.getTotalRefundAmt()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
itemData.put("refundAmount", refundAmount);
//手续费
if (record.getTotalFeeAmt() != null){
BigDecimal totalfeeamt = BigDecimal.valueOf(record.getTotalFeeAmt()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
itemData.put("totalFeeAmt", totalfeeamt);
}
//手续费回退
if (record.getTotalRefundFeeAmt() != null){
BigDecimal totalReFeeAmt= BigDecimal.valueOf(record.getTotalRefundFeeAmt()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
itemData.put("totalRefundFeeAmt", totalReFeeAmt);
}
// 成功率
itemData.put("round", record.getSuccRate() + "%");
if (StringUtils.isNotBlank(record.getDeviceType())) {
itemData.put("deviceType", PayOrder.DEVICE_TYPE_MAP.get(record.getDeviceType()));
}
newList.add(itemData);
});
List<T> linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), clazz);
// excel输出
ExcelUtil.exportExcel(linkedList, title, title, clazz, title, response);
}catch (Exception e) {
logger.error("导出excel失败", e);
throw new BizException("导出订单失败!");
}
}
}

View File

@@ -0,0 +1,98 @@
package com.jeequan.jeepay.agent.ctrl.statistics;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.PayOrderCount;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.PayOrder;
import com.jeequan.jeepay.service.impl.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 统计列表接口
*
* @author xiaoyu
*
* @date 2022/5/23 16:52
*/
@Slf4j
@RestController
@RequestMapping("/api/statistic")
public class StatisticController extends CommonCtrl {
@Autowired private PayOrderService payOrderService;
@Autowired private AgentInfoService agentInfoService;
@Autowired private StatsTradeService statsTradeService;
@Autowired private StatsChannelService statsChannelService;
@Autowired private StatsPayWayService statsPayWayService;
@Autowired private StatsDeviceService statsDeviceService;
/**
* @author: xiaoyu
* @date: 2022/5/23 17:15
* @describe: 统计列表
*/
@PreAuthorize("hasAnyAuthority('ENT_STATISTIC_TRANSACTION', 'ENT_STATISTIC_MCH', 'ENT_STATISTIC_MCH_STORE', 'ENT_STATISTIC_MCH_WAY', 'ENT_STATISTIC_MCH_TYPE', 'ENT_STATISTIC_AGENT', 'ENT_STATISTIC_CHANNEL')")
@RequestMapping(value="", method = RequestMethod.GET)
public ApiRes list() {
JSONObject paramJSON = getReqParamJSON();
PayOrder payOrder = getObject(PayOrder.class);
List<String> agentSubList = null;
// 交易报表
if (StringUtils.isEmpty(payOrder.getAgentNo())) {
// 查询服务商所有下级
agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
}
String method = getValStringRequired("method");
String mchNo = null;
Page<PayOrderCount> mapPage = new Page<>();
switch (method) {
case CS.STATISTIC_TYPE.MCH:
// 商户
mapPage = statsTradeService.selectMchStatsList(paramJSON, agentSubList);
break;
case CS.STATISTIC_TYPE.AGENT:
// 服务商
mapPage = statsTradeService.selectAgentStatsList(paramJSON, agentSubList);
break;
case CS.STATISTIC_TYPE.TRANSACTION:
mapPage = statsTradeService.selectTransactionStatsList(payOrder, paramJSON, agentSubList);
break;
case CS.STATISTIC_TYPE.STORE:
// 门店
getValStringRequired("mchNo");
mapPage = statsTradeService.selectStoreStatsList(paramJSON);
break;
case CS.STATISTIC_TYPE.WAY_CODE:
// 支付方式
getValStringRequired("mchNo");
mapPage = statsPayWayService.selectPayWayStatsList(paramJSON);
break;
case CS.STATISTIC_TYPE.WAY_CODE_TYPE:
// 支付类型
getValStringRequired("mchNo");
mapPage = statsPayWayService.selectWayCodeTypeStatsList(paramJSON);
break;
case CS.STATISTIC_TYPE.DEVICE:
// 设备
mapPage = statsDeviceService.selectStatsList(paramJSON, agentSubList);
break;
default:
break;
}
// 解决hasnext不显示的问题
mapPage.setCurrent(paramJSON.getIntValue("pageNumber"));
mapPage.setSize(paramJSON.getIntValue("pageSize"));
return ApiRes.page(mapPage);
}
}

View File

@@ -0,0 +1,109 @@
package com.jeequan.jeepay.agent.ctrl.statistics;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.PayOrderCount;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.PayOrder;
import com.jeequan.jeepay.service.impl.AgentInfoService;
import com.jeequan.jeepay.service.impl.StatsDeviceService;
import com.jeequan.jeepay.service.impl.StatsPayWayService;
import com.jeequan.jeepay.service.impl.StatsTradeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 总计接口
*
* @author xiaoyu
*
* @date 2022/5/23 16:52
*/
@Slf4j
@RestController
@RequestMapping("/api/statistic/total")
public class TotalStatisticController extends CommonCtrl {
@Autowired private AgentInfoService agentInfoService;
@Autowired private StatsTradeService statsTradeService;
@Autowired private StatsPayWayService statsPayWayService;
@Autowired private StatsDeviceService statsDeviceService;
/**
* @author: xiaoyu
* @date: 2022/5/23 17:15
* @describe: 总计
*/
@PreAuthorize("hasAnyAuthority('ENT_STATISTIC_TRANSACTION', 'ENT_STATISTIC_MCH', 'ENT_STATISTIC_MCH_STORE', 'ENT_STATISTIC_MCH_WAY', 'ENT_STATISTIC_MCH_TYPE', 'ENT_STATISTIC_AGENT', 'ENT_STATISTIC_CHANNEL')")
@RequestMapping(value="", method = RequestMethod.GET)
public ApiRes total() {
JSONObject paramJSON = getReqParamJSON();
PayOrder payOrder = getObject(PayOrder.class);
List<String> agentSubList = null;
if (StringUtils.isEmpty(payOrder.getAgentNo())) {
// 查询服务商所有下级
agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
}else {
}
String method = getValStringRequired("method");
String mchNo = null;
PayOrderCount orderCount = new PayOrderCount();
switch (method) {
case CS.STATISTIC_TYPE.MCH:
// 商户统计
// resMap = payOrderService.totalByMch(payOrder, paramJSON, agentSubList);
orderCount = statsTradeService.selectTotalByTransaction(paramJSON, agentSubList);
break;
case CS.STATISTIC_TYPE.AGENT:
// 服务商统计
// resMap = payOrderService.totalByAgent(payOrder, paramJSON, agentSubList);
orderCount = statsTradeService.selectTotalByAgent(paramJSON, agentSubList);
break;
case CS.STATISTIC_TYPE.TRANSACTION:
// 交易报表统计
// resMap = payOrderService.totalByTransaction(payOrder, paramJSON, agentSubList);
orderCount = statsTradeService.selectTotalByTransaction(paramJSON, agentSubList, false);
break;
case CS.STATISTIC_TYPE.STORE:
// 门店统计
getValStringRequired("mchNo");
// payOrder.setMchNo(mchNo);
// resMap = payOrderService.totalByStore(payOrder, paramJSON);
orderCount = statsTradeService.selectTotalByStore(paramJSON, null);
break;
case CS.STATISTIC_TYPE.WAY_CODE:
// 支付方式统计
getValStringRequired("mchNo");
// payOrder.setMchNo(mchNo);
// resMap = payOrderService.totalByWayCode(payOrder, paramJSON);
orderCount = statsPayWayService.selectTotalByPayWay(paramJSON);
break;
case CS.STATISTIC_TYPE.WAY_CODE_TYPE:
// 支付类型统计
getValStringRequired("mchNo");
// payOrder.setMchNo(mchNo);
// resMap = payOrderService.totalByWayCodeType(payOrder, paramJSON);
orderCount = statsPayWayService.selectTotalByWayCodeType(paramJSON);
break;
case CS.STATISTIC_TYPE.DEVICE:
// 设备统计
// resMap = payOrderService.totalByDevice(payOrder, paramJSON, agentSubList);
orderCount = statsDeviceService.selectTotalByDeviceNo(paramJSON, agentSubList);
break;
default:
break;
}
return ApiRes.ok(orderCount);
}
}

View File

@@ -0,0 +1,56 @@
package com.jeequan.jeepay.agent.ctrl.store;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.DeviceProvideConfig;
import com.jeequan.jeepay.service.impl.DeviceProvideConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 设备厂商配置管理类
*
* @author zx
* @date 2021-12-28 09:15
*/
@Slf4j
@RestController
@RequestMapping("api/device/provider")
public class DeviceProvideConfigController extends CommonCtrl {
@Autowired private DeviceProvideConfigService deviceProvideConfigService;
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 厂商配置列表
*/
@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_LIST', 'ENT_DEVICE_PRINTER_LIST', 'ENT_DEVICE_SPEAKER_ADD'," +
"'ENT_DEVICE_PRINTER_ADD', 'ENT_DEVICE_SPEAKER_EDIT', 'ENT_DEVICE_PRINTER_EDIT')")
@GetMapping
public ApiRes pages() {
LambdaQueryWrapper<DeviceProvideConfig> gw = DeviceProvideConfig.gw();
gw.select(DeviceProvideConfig::getConfigId, DeviceProvideConfig::getConfigDesc, DeviceProvideConfig::getProvider);
gw.orderByDesc(DeviceProvideConfig::getCreatedAt);
gw.eq(DeviceProvideConfig::getDeviceType, getValByteRequired("deviceType"));
if (null != getValByte("state")) {
gw.eq(DeviceProvideConfig::getState, getValByte("state"));
}
gw.select(DeviceProvideConfig::getConfigId, DeviceProvideConfig::getConfigDesc, DeviceProvideConfig::getDeviceType, DeviceProvideConfig::getProvider,
DeviceProvideConfig::getCreatedAt, DeviceProvideConfig::getAppId, DeviceProvideConfig::getState);
IPage<DeviceProvideConfig> page = deviceProvideConfigService.page(getIPage(true), gw);
//返回数据
return ApiRes.page(page);
}
}

View File

@@ -0,0 +1,201 @@
package com.jeequan.jeepay.agent.ctrl.store;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.DBApiMapConfig;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.MchApplyment;
import com.jeequan.jeepay.db.entity.MchInfo;
import com.jeequan.jeepay.db.entity.MchStore;
import com.jeequan.jeepay.service.impl.AgentInfoService;
import com.jeequan.jeepay.service.impl.MchApplymentService;
import com.jeequan.jeepay.service.impl.MchInfoService;
import com.jeequan.jeepay.service.impl.MchStoreService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* 商户门店管理
*
* @date 2021/12/29 9:52
*/
@RestController
@RequestMapping("/api/mchStore")
public class MchStoreController extends CommonCtrl {
@Autowired private MchStoreService mchStoreService;
@Autowired private AgentInfoService agentInfoService;
@Autowired private MchInfoService mchInfoService;
@Autowired
private MchApplymentService mchApplymentService;
/**
* @date: 2021/12/29 9:53
* @describe: 门店列表查询
*/
@GetMapping
@PreAuthorize("hasAuthority('ENT_MCH_STORE_LIST')")
public ApiRes list() {
MchStore mchStore = getObject(MchStore.class);
//mchStore.setAgentNo(getCurrentAgentNo());
JSONObject paramJSON = getReqParamJSON();
// 可查看自己和全部下级服务商
String currentAgentNo = getCurrentAgentNo();
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
if (CollectionUtil.isNotEmpty(subAgentNoList)) {
mchStore.setSubAgentNoList(subAgentNoList);
}
IPage<MchStore> mchStoreList = mchStoreService.listByPage(getIPage(true), mchStore, paramJSON);
return ApiRes.page(mchStoreList);
}
/**
* @date: 2021/12/29 9:59
* @describe: 新建门店
*/
@MethodLog(remark = "新建门店")
@PostMapping
@PreAuthorize("hasAuthority('ENT_MCH_STORE_ADD')")
public ApiRes add() {
MchStore mchStore = getObject(MchStore.class);
Assert.hasLength(mchStore.getMchNo(), "用户号[mchNo]不能为空");
Assert.notNull(mchStore.getAreaCode(), "请选择省市区");
AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());
Assert.hasLength(mchStore.getMchApplyId(), "商户号[mchApplyId]不能为空");
MchApplyment tbMchApplyment = mchApplymentService.getById(mchStore.getMchApplyId());
Assert.notNull(tbMchApplyment, "商户不存在");
//关联商户信息原进件信息t_mch_applyment需要校验商户状态必须是进件成功的
if (MchApplyment.STATE_SUCCESS != tbMchApplyment.getState()) {
return ApiRes.customFail("该商户状态未进件成功!");
}
//校验指定商户号下的进件信息
String applyMchNo = tbMchApplyment.getMchNo();
String storeMchNo = mchStore.getMchNo();
if (!applyMchNo.equals(storeMchNo)) {
return ApiRes.customFail("用户信息与商户信息不匹配!");
}
mchStore.setStoreId(SeqKit.genStoreNo());
mchStore.setAgentNo(agentInfo.getAgentNo());
mchStore.setTopAgentNo(agentInfoService.queryTopAgentNo(getCurrentAgentNo()));
mchStore.setIsvNo(agentInfo.getIsvNo());
// 初始为非默认门店
mchStore.setDefaultFlag(CS.NO);
boolean result = mchStoreService.save(mchStore);
if (!result) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_CREATE);
}
return ApiRes.ok();
}
/**
* @date: 2021/12/29 9:59
* @describe: 门店详情
*/
@GetMapping("/{recordId}")
@PreAuthorize("hasAuthority('ENT_MCH_STORE_VIEW')")
public ApiRes detail(@PathVariable("recordId") String recordId) {
MchStore mchStore = mchStoreService.getById(recordId);
if (mchStore == null || !mchStore.getAgentNo().equals(getCurrentAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
MchInfo mchInfo = mchInfoService.getById(mchStore.getMchNo());
mchStore.addExt("mchName", mchInfo.getMchName());
return ApiRes.ok(mchStore);
}
/**
* @date: 2021/12/29 10:00
* @describe: 更新门店
*/
@MethodLog(remark = "更新门店")
@PutMapping("/{recordId}")
@PreAuthorize("hasAuthority('ENT_MCH_STORE_EDIT')")
public ApiRes update(@PathVariable("recordId") String recordId) {
MchStore mchStore = getObject(MchStore.class);
mchStore.setStoreId(recordId);
mchStore.setMchNo(null);
mchStore.setAgentNo(null);
mchStore.setTopAgentNo(null);
mchStore.setCreatedAt(null);
mchStore.setUpdatedAt(null);
MchStore dbRecord = mchStoreService.getById(recordId);
if (!dbRecord.getAgentNo().equals(getCurrentAgentNo())) {
throw new BizException("无权操作!");
}
// 如果修改当前为默认
if (mchStore.getDefaultFlag() == CS.YES) {
mchStoreService.updateAllDefaultFlag(dbRecord.getMchNo());
}else {
mchStore.setDefaultFlag(null);
}
boolean result = mchStoreService.updateById(mchStore);
if (!result) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
}
return ApiRes.ok();
}
/**
* @date: 2021/12/29 10:05
* @describe: 删除门店
*/
@MethodLog(remark = "删除门店")
@DeleteMapping("/{recordId}")
@PreAuthorize("hasAuthority('ENT_MCH_STORE_DELETE')")
public ApiRes delete(@PathVariable("recordId") String recordId) {
MchStore mchStore = mchStoreService.getById(recordId);
if (!mchStore.getAgentNo().equals(getCurrentAgentNo())) {
throw new BizException("无权操作!");
}
if (mchStore.getDefaultFlag() == CS.YES) {
throw new BizException("默认门店无法删除!");
}
mchStoreService.deleteStore(recordId, false);
return ApiRes.ok();
}
/**
* @date: 2022/2/19 10:41
* @describe: 获取地图配置参数
*/
@GetMapping("/mapConfig")
@PreAuthorize("hasAuthority('ENT_MCH_STORE_MAP')")
public ApiRes getMapConfig() {
DBApiMapConfig apiMapConfig = sysConfigService.getDBApiMapConfig();
return ApiRes.ok(apiMapConfig);
}
}

View File

@@ -0,0 +1,466 @@
package com.jeequan.jeepay.agent.ctrl.store;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.interfaces.device.IPrinterService;
import com.jeequan.jeepay.core.interfaces.device.ISpeakerService;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device;
import com.jeequan.jeepay.core.utils.DateKit;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.service.impl.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 设备厂商配置管理类
*
* @author zx
*
* @date 2021-12-28 09:15
*/
@Slf4j
@RestController
@RequestMapping("api/store/device")
public class MchStoreDeviceController extends CommonCtrl {
@Autowired private DeviceProvideConfigService deviceProvideConfigService;
@Autowired private MchStoreDeviceService mchStoreDeviceService;
@Autowired private MchStoreService mchStoreService;
@Autowired private MchAppService mchAppService;
@Autowired private MchQrcDeviceRelaService mchQrcDeviceRelaService;
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 门店设备列表
*/
@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_LIST', 'ENT_DEVICE_PRINTER_DEVICE_LIST', 'ENT_DEVICE_POS_DEVICE_LIST', " +
"'ENT_DEVICE_PLUGIN_CDKEY_LIST', 'ENT_DEVICE_FACE_APP_LIST')")
@GetMapping
public ApiRes pages() {
MchStoreDevice mchStoreDevice = getObject(MchStoreDevice.class);
// 可查看自己和全部下级代理的设备
String currentAgentNo = getCurrentAgentNo();
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
if (CollectionUtil.isNotEmpty(subAgentNoList)) {
mchStoreDevice.setSubAgentNoList(subAgentNoList);
}
IPage<MchStoreDevice> page = mchStoreDeviceService.selectPage(getIPage(), mchStoreDevice);
if (page.getTotal() == 0) {
return ApiRes.page(page);
}
// 列表添加是否属于自身设备只能绑定直属商户app端展示隐藏也使用此字段
for (MchStoreDevice device: page.getRecords()) {
if (currentAgentNo.equals(device.getAgentNo())) {
device.addExt("isSelf", true);
}
}
//返回数据
return ApiRes.page(page);
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 门店设备修改
*/
@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_EDIT', 'ENT_DEVICE_PRINTER_DEVICE_EDIT', 'ENT_DEVICE_POS_DEVICE_EDIT', " +
"'ENT_DEVICE_PLUGIN_CDKEY_EDIT', 'ENT_DEVICE_FACE_APP_EDIT')")
@MethodLog(remark = "设备厂商配置修改")
@PutMapping("/{deviceId}")
public ApiRes update(@PathVariable("deviceId") Long deviceId) {
MchStoreDevice mchStoreDevice = getObject(MchStoreDevice.class);
mchStoreDevice.setDeviceId(deviceId);
mchStoreDevice.setBatchId(null);
mchStoreDevice.setDeviceNo(null);
mchStoreDevice.setDeviceParams(null);
mchStoreDevice.setCreatedAt(null);
mchStoreDevice.setUpdatedAt(null);
// 可查看自己和全部下级代理的设备
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
MchStoreDevice dbRecord = mchStoreDeviceService.getById(deviceId);
if (!subAgentNoList.contains(dbRecord.getAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
boolean result = mchStoreDeviceService.updateById(mchStoreDevice);
if(!result) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
}
return ApiRes.ok();
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 根据ID获取门店设备
*/
@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_VIEW', 'ENT_DEVICE_PRINTER_DEVICE_VIEW', 'ENT_DEVICE_POS_DEVICE_VIEW', " +
"'ENT_DEVICE_PLUGIN_CDKEY_VIEW', 'ENT_DEVICE_FACE_APP_VIEW')")
@GetMapping("/{deviceId}")
public ApiRes get(@PathVariable("deviceId") Long deviceId) {
// 可查看自己和全部下级代理的设备
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
MchStoreDevice dbRecord = mchStoreDeviceService.getById(deviceId);
if (!subAgentNoList.contains(dbRecord.getAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
// 设备是否属于自身
if (getCurrentAgentNo().equals(dbRecord.getAgentNo())) {
dbRecord.addExt("isSelf", true);
}
// 添加服务商、商户、门店名称
AgentInfo allotAgent = agentInfoService.getById(dbRecord.getAgentNo());
if (allotAgent != null) {
dbRecord.addExt("agentName", allotAgent.getAgentName());
}
if (dbRecord.getBindState() == CS.YES) {
if (StringUtils.isNotBlank(dbRecord.getMchNo())) {
MchInfo mchInfo = mchInfoService.getById(dbRecord.getMchNo());
if (mchInfo != null) {
dbRecord.addExt("mchName", mchInfo.getMchName());
}
}
if (StringUtils.isNotBlank(dbRecord.getAppId())) {
MchAppEntity mchAppEntity = mchAppService.getById(dbRecord.getAppId());
if (mchAppEntity != null) {
dbRecord.addExt("appName", mchAppEntity.getAppName());
}
}
if (dbRecord.getStoreId() != null) {
MchStore mchStore = mchStoreService.getById(dbRecord.getStoreId());
if (mchStore != null) {
dbRecord.addExt("storeName", mchStore.getStoreName());
}
}
}
List<MchQrcDeviceRela> relaList = mchQrcDeviceRelaService.list(MchQrcDeviceRela.gw().eq(MchQrcDeviceRela::getDeviceId, deviceId));
if (!CollectionUtils.isEmpty(relaList)) {
dbRecord.addExt("qrcIdList", relaList.stream().map(MchQrcDeviceRela::getQrcId).collect(Collectors.toList()));
}
return ApiRes.ok(dbRecord);
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 播报测试
*/
@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_TEST')")
@PostMapping("/speak/{deviceId}")
public ApiRes speak(@PathVariable("deviceId") Long deviceId) {
Long amountL = getRequiredAmountL("amount");
// 可查看自己和全部下级代理的设备
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
MchStoreDevice mchStoreDevice = mchStoreDeviceService.getById(deviceId);
if (mchStoreDevice == null || mchStoreDevice.getState() != CS.YES || !subAgentNoList.contains(mchStoreDevice.getAgentNo())) {
return ApiRes.customFail("设备不存在或已禁用");
}
DeviceProvideConfig provideConfig = deviceProvideConfigService.getById(mchStoreDevice.getConfigId());
if (provideConfig == null || provideConfig.getState() != CS.YES) {
return ApiRes.customFail("设备厂商未配置或已禁用");
}
// 设备类型
String provider = mchStoreDevice.getProvider();
ISpeakerService speakerService = SpringBeansUtil.getBean(provider + "SpeakerService", ISpeakerService.class);
// 设备参数
JSONObject deviceParams = new JSONObject();
deviceParams.put("deviceParams", mchStoreDevice.getDeviceParams());
deviceParams.put("bizConfigParams", mchStoreDevice.getBizConfigParams());
deviceParams.put("providerParams", provideConfig.getProviderParams());
// 消息内容
PayOrderInfo4Device speakPayOrderInfo = new PayOrderInfo4Device();
speakPayOrderInfo.setAmount(amountL);
speakPayOrderInfo.setWayCodeType(CS.PAY_WAY_CODE_TYPE.WECHAT);
speakPayOrderInfo.setPayOrderId(String.valueOf(DateKit.currentTimeMillis()));
try {
speakerService.send(deviceParams, speakPayOrderInfo);
return ApiRes.ok();
}catch (BizException e) {
throw e;
}
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 打印测试
*/
@PreAuthorize("hasAnyAuthority('ENT_DEVICE_PRINTER_DEVICE_TEST')")
@PostMapping("/print/{deviceId}")
public ApiRes print(@PathVariable("deviceId") Long deviceId) {
Long amountL = getRequiredAmountL("amount");
// 可查看自己和全部下级代理的设备
List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
MchStoreDevice mchStoreDevice = mchStoreDeviceService.getById(deviceId);
if (mchStoreDevice == null || mchStoreDevice.getState() != CS.YES || !subAgentNoList.contains(mchStoreDevice.getAgentNo())) {
return ApiRes.customFail("设备不存在或已禁用");
}
DeviceProvideConfig provideConfig = deviceProvideConfigService.getById(mchStoreDevice.getConfigId());
if (provideConfig == null || provideConfig.getState() != CS.YES) {
return ApiRes.customFail("设备厂商未配置或已禁用");
}
// 设备类型
String provider = mchStoreDevice.getProvider();
IPrinterService printerService = SpringBeansUtil.getBean(provider + "PrinterService", IPrinterService.class);
// 设备参数
JSONObject deviceParams = new JSONObject();
deviceParams.put("deviceParams", mchStoreDevice.getDeviceParams());
deviceParams.put("bizConfigParams", mchStoreDevice.getBizConfigParams());
deviceParams.put("providerParams", provideConfig.getProviderParams());
// 消息内容
PayOrderInfo4Device printPayOrderInfo = new PayOrderInfo4Device();
printPayOrderInfo.setAmount(amountL);
printPayOrderInfo.setWayCodeType(CS.PAY_WAY_CODE_TYPE.WECHAT);
printPayOrderInfo.setPayOrderId(String.valueOf(DateKit.currentTimeMillis()));
printPayOrderInfo.setCreatedAt(DateUtil.date());
try {
printerService.send(deviceParams, printPayOrderInfo);
return ApiRes.ok();
}catch (BizException e) {
throw e;
}
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 清空打印队列
*/
@PreAuthorize("hasAnyAuthority('ENT_DEVICE_PRINTER_DEVICE_CLEAR')")
@PostMapping("/clear/{deviceId}")
public ApiRes clear(@PathVariable("deviceId") Long deviceId) {
MchStoreDevice mchStoreDevice = mchStoreDeviceService.getById(deviceId);
if (mchStoreDevice == null || mchStoreDevice.getState() != CS.YES) {
return ApiRes.customFail("设备不存在");
}
DeviceProvideConfig provideConfig = deviceProvideConfigService.getById(mchStoreDevice.getConfigId());
if (provideConfig == null || provideConfig.getState() != CS.YES) {
return ApiRes.customFail("设备厂商未配置");
}
// 设备类型
String provider = mchStoreDevice.getProvider();
IPrinterService printerService = SpringBeansUtil.getBean(provider + "PrinterService", IPrinterService.class);
// 设备参数
JSONObject deviceParams = new JSONObject();
deviceParams.put("deviceParams", mchStoreDevice.getDeviceParams());
deviceParams.put("bizConfigParams", mchStoreDevice.getBizConfigParams());
deviceParams.put("providerParams", provideConfig.getProviderParams());
try {
printerService.clearPrinter(deviceParams);
return ApiRes.ok();
}catch (Exception e) {
return ApiRes.customFail(e.getMessage());
}
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 绑定设备
*/
@MethodLog(remark = "绑定设备")
@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_EDIT', 'ENT_DEVICE_PRINTER_DEVICE_EDIT', 'ENT_DEVICE_POS_DEVICE_EDIT'," +
"'ENT_DEVICE_PLUGIN_CDKEY_EDIT', 'ENT_DEVICE_FACE_APP_EDIT')")
@PutMapping("/bind/{deviceId}")
public ApiRes bind(@PathVariable("deviceId") Long deviceId) {
String mchNo = getValStringRequired("mchNo");
String storeId = getValStringRequired("storeId");
Byte bindType = getValByte("bindType");
MchInfo mchInfo = mchInfoService.getById(mchNo);
if (mchInfo == null || StringUtils.isBlank(mchInfo.getAgentNo()) || !mchInfo.getAgentNo().equals(getCurrentAgentNo())) {
throw new BizException("商户不存在");
}
MchStoreDevice dbRecord = mchStoreDeviceService.getById(deviceId);
if (dbRecord == null || StringUtils.isBlank(dbRecord.getAgentNo()) || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
// 除云喇叭和云打印外的设备 需绑定商户应用
String appId = "";
if (dbRecord.getDeviceType() != MchStoreDevice.DEVICE_TYPE_SPEAKER && dbRecord.getDeviceType() != MchStoreDevice.DEVICE_TYPE_PRINTER) {
appId = getValStringRequired("appId");
}
MchStoreDevice updateRecord = new MchStoreDevice();
updateRecord.setDeviceId(deviceId).setMchNo(mchNo).setAppId(appId).setStoreId(storeId).setBindState(CS.YES);
if (null != bindType) {
updateRecord.setBindType(bindType);
}
// 云喇叭 同步绑定码牌
if (dbRecord.getDeviceType() == MchStoreDevice.DEVICE_TYPE_SPEAKER) {
String qrcIdListStr = getValString("qrcIdList");
// 云喇叭绑定类型 为码牌时需传入绑定的码牌id
List<Long> qrcList = new LinkedList<>();
if (null != bindType && bindType == MchStoreDevice.DEVICE_BIND_TYPE_QRC && StringUtils.isNotBlank(qrcIdListStr)) {
qrcList = JSONArray.parseArray(qrcIdListStr, Long.class);
}
boolean result = mchStoreDeviceService.bindSpeakerDevice(updateRecord, dbRecord.getBindQrcId(), qrcList);
if (!result) {
return ApiRes.customFail("绑定失败");
}
return ApiRes.ok();
}
// 云打印、扫码pos执行更新
if (mchStoreDeviceService.updateById(updateRecord)) {
return ApiRes.ok();
}
return ApiRes.customFail("绑定失败");
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 解绑设备
*/
@MethodLog(remark = "解绑设备")
@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_EDIT', 'ENT_DEVICE_PRINTER_DEVICE_EDIT', 'ENT_DEVICE_POS_DEVICE_EDIT'," +
" 'ENT_DEVICE_PLUGIN_CDKEY_EDIT', 'ENT_DEVICE_FACE_APP_EDIT')")
@PostMapping("/unbind/{deviceId}")
public ApiRes unbind(@PathVariable("deviceId") Long deviceId) {
MchStoreDevice dbRecord = mchStoreDeviceService.getById(deviceId);
if (dbRecord == null || dbRecord.getBindState() == CS.NO || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) {
return ApiRes.customFail("解绑失败");
}
MchInfo mchInfo = mchInfoService.getById(dbRecord.getMchNo());
if (mchInfo == null || StringUtils.isBlank(mchInfo.getAgentNo()) || !mchInfo.getAgentNo().equals(getCurrentAgentNo())) {
throw new BizException("当前解绑设备不属于您的直属商户,无法解绑!");
}
mchStoreDeviceService.unbind(dbRecord);
return ApiRes.ok();
}
/**
* @author: zx
* @date: 2021-12-28 09:15
* @describe: 划拨/收回设备
*/
@MethodLog(remark = "划拨/收回设备")
@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_ALLOT', 'ENT_DEVICE_PRINTER_DEVICE_ALLOT', " +
"'ENT_DEVICE_POS_DEVICE_ALLOT', 'ENT_DEVICE_PLUGIN_CDKEY_ALLOT', 'ENT_DEVICE_FACE_APP_ALLOT')")
@PostMapping("/allotDevice")
public ApiRes allotDevice() {
// 服务商是否支持划拨码牌、设备
SysConfig isSupportAgentAllot = sysConfigService.getById("isSupportAgentAllot");
if(isSupportAgentAllot == null || String.valueOf(CS.NO).equals(isSupportAgentAllot.getConfigVal())){
throw new BizException("不支持服务商划拨码牌、设备");
}
String allotType = getValStringRequired("allotType"); // 划拨类型select-勾选划拨 batch-批次划拨
String allotOrRecover = getValStringRequired("allotOrRecover"); // 分配类型allot-划拨 recover-收回
// 构建批量更新设备ID集合
List<MchStoreDevice> list;
if (allotType.equals("select")) {
String allotDeviceIds = getValStringRequired("allotDeviceIds");
list = mchStoreDeviceService.list(MchStoreDevice.gw().in(MchStoreDevice::getDeviceId, Arrays.asList(allotDeviceIds.split(","))));
}else if (allotType.equals("batch")) {
String batchId = getValStringRequired("batchId");
list = mchStoreDeviceService.list(MchStoreDevice.gw().eq(MchStoreDevice::getBatchId, batchId));
}else {
throw new BizException("划拨类型错误");
}
if (CollUtil.isEmpty(list)) {
throw new BizException("请选择设备");
}
// 当前代理只可划拨自己和直接下级代理的设备
List<String> subAgentNoList = agentInfoService.querySubAgentNo(getCurrentAgentNo());
for (MchStoreDevice mchStoreDevice: list) {
if (!subAgentNoList.contains(mchStoreDevice.getAgentNo())) {
throw new BizException("存在不可划拨设备【设备号:" + mchStoreDevice.getDeviceNo() + "");
}
}
List<Long> deviceIdList = list.stream().map(MchStoreDevice::getDeviceId).collect(Collectors.toList());
// 1、收回设备
if (allotOrRecover.equals("recover")) {
mchStoreDeviceService.recoverDevice(true, deviceIdList, subAgentNoList, getCurrentAgentNo());
return ApiRes.ok();
}
// 2、划拨设备
String agentNo = getValStringRequired("agentNo");
List<String> mchNoList = getMchNoListByAgentNo(agentNo);
mchStoreDeviceService.allotDevice(true, agentNo, deviceIdList, mchNoList, subAgentNoList);
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,159 @@
package com.jeequan.jeepay.agent.ctrl.subagent;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.MchInfo;
import com.jeequan.jeepay.db.entity.SysAdvertConfig;
import com.jeequan.jeepay.service.impl.SysAdvertConfigService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 广告
*
* @author xiaoyu
*
* @date 2023/2/21 16:13
*/
@RestController
@RequestMapping("/api/advert")
public class AdvertController extends CommonCtrl {
@Autowired SysAdvertConfigService advertConfigService;
/** APP 展业宝广告 **/
@GetMapping("/appAdvert")
public ApiRes appAdvert() {
// 广告位置 1-启动页 2-首页 3-我的页
Byte appPlace = getValByteRequired("appPlace");
// 查询平台全局广告
LambdaQueryWrapper<SysAdvertConfig> wrapper = SysAdvertConfig.gw();
wrapper.eq(SysAdvertConfig::getAdvertType, SysAdvertConfig.ADVERT_TYPE_APP_AGENT);
wrapper.eq(SysAdvertConfig::getAppPlace, appPlace);
wrapper.eq(SysAdvertConfig::getReleaseState, CS.YES);
wrapper.orderByAsc(SysAdvertConfig::getAdvertSort);
wrapper.orderByDesc(SysAdvertConfig::getCreatedAt);
List<SysAdvertConfig> list = advertConfigService.list(wrapper);
return ApiRes.ok(list);
}
/**
* @author: xiaoyu
* @date: 2023/2/20 11:06
* @describe: 广告配置列表
*/
@PreAuthorize("hasAnyAuthority('ENT_ADVERT_LIST', 'ENT_ADVERT_VIEW')")
@GetMapping
public ApiRes pages() {
SysAdvertConfig record = getObject(SysAdvertConfig.class);
LambdaQueryWrapper<SysAdvertConfig> condition = SysAdvertConfig.gw();
condition.eq(record.getAdvertId() != null, SysAdvertConfig::getAdvertId, record.getAdvertId());
condition.eq(record.getAppPlaceType() != null, SysAdvertConfig::getAppPlaceType, record.getAppPlaceType());
condition.eq(record.getReleaseState() != null, SysAdvertConfig::getReleaseState, record.getReleaseState());
condition.eq(record.getAdvertType() != null, SysAdvertConfig::getAdvertType, record.getAdvertType());
condition.eq(record.getAppPlace() != null, SysAdvertConfig::getAppPlace, record.getAppPlace());
condition.like(StringUtils.isNotEmpty(record.getTitle()), SysAdvertConfig::getTitle, record.getTitle());
condition.eq(StringUtils.isNotEmpty(record.getMchNo()), SysAdvertConfig::getMchNo, record.getMchNo());
condition.eq(SysAdvertConfig::getAgentNo, getCurrentAgentNo());
condition.orderByDesc(SysAdvertConfig::getCreatedAt);
IPage<SysAdvertConfig> pages = advertConfigService.page(getIPage(), condition);
for (SysAdvertConfig config: pages.getRecords()) {
if (StringUtils.isNotEmpty(config.getMchNo())) {
MchInfo mchInfo = mchInfoService.getById(config.getMchNo());
if (mchInfo != null) {
config.addExt("infoName", mchInfo.getMchName());
}else {
config.addExt("infoName", "");
}
}
}
//返回数据
return ApiRes.ok(pages);
}
/** detail */
@PreAuthorize("hasAuthority( 'ENT_ADVERT_VIEW' )")
@RequestMapping(value="/{advertId}", method = RequestMethod.GET)
public ApiRes getConfigs(@PathVariable("advertId") Long advertId) {
SysAdvertConfig config = advertConfigService.getOne(
SysAdvertConfig.gw()
.eq(SysAdvertConfig::getAdvertId, advertId)
.eq(SysAdvertConfig::getAgentNo, getCurrentAgentNo())
);
return ApiRes.ok(config);
}
/**
* @author: xiaoyu
* @date: 2023/2/20 11:06
* @describe: 广告配置修改
*/
@PreAuthorize("hasAnyAuthority('ENT_ADVERT_EDIT')")
@MethodLog(remark = "广告配置修改")
@RequestMapping(value="/{advertId}", method = RequestMethod.PUT)
public ApiRes update(@PathVariable("advertId") Long advertId) {
// 校验权限
SysAdvertConfig config = advertConfigService.getById(advertId);
if (config != null && !getCurrentAgentNo().equals(config.getAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
SysAdvertConfig record = getObject(SysAdvertConfig.class);
record.setAdvertId(advertId);
if (getReqParamJSON().getByte("state") != null) {
record.setReleaseState(getReqParamJSON().getByte("state"));
}
advertConfigService.updateAdvert(record);
return ApiRes.ok();
}
/**
* @author: xiaoyu
* @date: 2023/2/20 11:10
* @describe: 广告配置新增
*/
@PreAuthorize("hasAuthority( 'ENT_ADVERT_ADD' )")
@MethodLog(remark = "广告配置新增")
@RequestMapping(value="", method = RequestMethod.POST)
public ApiRes add() {
JSONObject paramJSON = getReqParamJSON();
SysAdvertConfig record = getObject(SysAdvertConfig.class);
String infoIds = paramJSON.getString("infoIds");
record.setAgentNo(getCurrentAgentNo());
record.setCreatedUid(getCurrentUser().getSysUserId());
record.setCreatedBy(getCurrentUser().getSysUser().getRealname());
advertConfigService.addConfig(infoIds, record);
return ApiRes.ok();
}
/** delete */
@PreAuthorize("hasAuthority('ENT_ADVERT_DEL')")
@MethodLog(remark = "广告配置删除")
@DeleteMapping
public ApiRes del() {
String delAdvertIds = getValStringRequired("delAdvertIds");
List<String> advertIdList = Arrays.stream(delAdvertIds.split(",")).collect(Collectors.toList());
advertConfigService.removeConfig(advertIdList, getCurrentAgentNo(), CS.SYS_ROLE_TYPE.AGENT);
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,183 @@
package com.jeequan.jeepay.agent.ctrl.subagent;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager;
import com.jeequan.jeepay.components.mq.model.CleanAgentLoginAuthCacheMQ;
import com.jeequan.jeepay.components.mq.model.ResetIsvMchAppInfoConfigMQ;
import com.jeequan.jeepay.components.mq.vender.IMQSender;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.SysUser;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.smsconfig.SmsBizDiyContentModel;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.MchInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
/***
* 服务商管理
*
* @author terrfly
*
* @date 2022/3/15 15:25
*/
@RestController
@RequestMapping("/api/subAgents")
public class SubAgentInfoController extends CommonCtrl {
@Autowired private IMQSender mqSender;
@Autowired private SmsManager smsManager;
@PreAuthorize("hasAuthority('ENT_AGENT_LIST')")
@GetMapping
public ApiRes list() {
AgentInfo agentInfo = getObject(AgentInfo.class);
LambdaQueryWrapper<AgentInfo> wrapper = AgentInfo.gw();
wrapper.eq(AgentInfo::getPid, getCurrentAgentNo());
wrapper.eq(StringUtils.isNotEmpty(agentInfo.getAgentNo()), AgentInfo::getAgentNo, agentInfo.getAgentNo());
wrapper.eq(StringUtils.isNotEmpty(agentInfo.getIsvNo()), AgentInfo::getIsvNo, agentInfo.getIsvNo());
wrapper.like(StringUtils.isNotEmpty(agentInfo.getAgentName()), AgentInfo::getAgentName, agentInfo.getAgentName());
wrapper.eq(agentInfo.getState() != null, AgentInfo::getState, agentInfo.getState());
wrapper.like(StringUtils.isNotEmpty(agentInfo.getContactTel()), AgentInfo::getContactTel, agentInfo.getContactTel());
wrapper.like(StringUtils.isNotEmpty(agentInfo.getLoginUsername()), AgentInfo::getLoginUsername, agentInfo.getLoginUsername());
wrapper.orderByDesc(AgentInfo::getCreatedAt);
// app端 联合模糊查询字段
String unionAgentInfo = getValString("unionAgentInfo");
if (StringUtils.isNotBlank(unionAgentInfo)) {
wrapper.and(i -> i.like(AgentInfo::getAgentNo, unionAgentInfo)
.or().like(AgentInfo::getAgentName, unionAgentInfo)
.or().like(AgentInfo::getContactTel, unionAgentInfo));
}
IPage<AgentInfo> pages = agentInfoService.page(getIPage(), wrapper);
for (AgentInfo info:pages.getRecords()) {
info.setContactTel(DesensitizedUtil.mobilePhone(info.getContactTel()));
long count = mchInfoService.count(MchInfo.gw().eq(MchInfo::getAgentNo, info.getAgentNo()));
info.addExt("mchCount", count);
}
return ApiRes.page(pages);
}
@PreAuthorize("hasAuthority('ENT_AGENT_INFO_ADD')")
@MethodLog(remark = "新增服务商")
@PostMapping
public ApiRes add() {
// 当前服务商是否允许发展下级代理
AgentInfo pAgentInfo = agentInfoService.getById(getCurrentAgentNo());
if (pAgentInfo.getAddAgentFlag() != CS.YES) {
throw new BizException("当前服务商不可发展下级服务商");
}
AgentInfo agentInfo = getObject(AgentInfo.class);
agentInfo.setPid(getCurrentAgentNo());
AgentInfo thisAgent = agentInfoService.getById(getCurrentAgentNo());
agentInfo.setIsvNo(thisAgent.getIsvNo());
// 获取传入的服务商登录名、登录密码
String loginPassword = getValString("loginPassword");
Byte isNotify = getValByteRequired("isNotify");
if (StringUtils.isBlank(loginPassword)) {
loginPassword = null;
}
agentInfo.setAgentNo("P" + DateUtil.format(new Date(), "yyMMdd")+ RandomUtil.randomNumbers(6));
// 当前登录用户信息
SysUser sysUser = getCurrentUser().getSysUser();
agentInfo.setCreatedUid(sysUser.getSysUserId());
agentInfo.setCreatedBy(sysUser.getRealname());
agentInfoService.addAgentV2(agentInfo, loginPassword, true);
// 发送短信通知
if (isNotify == CS.YES) {
smsManager.sendDiyContentSms(SmsBizDiyContentModel.genUserOpenAccount(agentInfo.getContactTel(), agentInfo.getLoginUsername(), loginPassword));
}
return ApiRes.ok();
}
@PreAuthorize("hasAuthority('ENT_AGENT_INFO_DEL')")
@MethodLog(remark = "删除服务商")
@DeleteMapping(value="/{agentNo}")
public ApiRes delete(@PathVariable("agentNo") String agentNo) {
List<Long> userIdList = agentInfoService.removeByAgentNo(agentNo);
// 推送mq删除redis用户缓存
mqSender.send(CleanAgentLoginAuthCacheMQ.build(userIdList));
return ApiRes.ok();
}
@PreAuthorize("hasAuthority('ENT_AGENT_INFO_EDIT')")
@MethodLog(remark = "更新服务商信息")
@PutMapping(value="/{agentNo}")
public ApiRes update(@PathVariable("agentNo") String agentNo) {
AgentInfo dbAgentInfo = agentInfoService.getById(agentNo);
if (dbAgentInfo == null) {
throw new BizException("服务商信息不存在");
}
//获取查询条件
AgentInfo agentInfo = getObject(AgentInfo.class);
agentInfo.setAgentNo(agentNo); //设置服务商号主键
agentInfo.setIsvNo(null); // 不允许更改
agentInfo.setPid(null);
agentInfo.setLoginUsername(null); // 防止修改用户登录名
boolean resetPass = getReqParamJSON().getBooleanValue("resetPass");
String confirmPwd = null;
if(resetPass){
confirmPwd = Boolean.TRUE.equals(getReqParamJSON().getBoolean("defaultPass")) ? null : Base64.decodeStr(getValStringRequired("confirmPwd"));
}
// 判断要修改的服务商信息是否需要审核 如果为审核失败/待认证->待审核
if (dbAgentInfo.getState() == AgentInfo.AUDIT_STATE_FALSE || dbAgentInfo.getState() == AgentInfo.AUDIT_STATE_UN_AUTH) {
agentInfo.setState(AgentInfo.AUDIT_STATE_ING);
}
// 更新 & 得到需要删除的用户ID的记录
Set<Long> removeCacheUserIdList = agentInfoService.updateAgent(agentInfo, getReqParamJSON(), resetPass, confirmPwd);
// 推送mq删除redis用户认证信息
if (!removeCacheUserIdList.isEmpty()) {
mqSender.send(CleanAgentLoginAuthCacheMQ.build(new ArrayList<>(removeCacheUserIdList)));
}
// 推送mq到目前节点进行更新数据
mqSender.send(ResetIsvMchAppInfoConfigMQ.build(ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_INFO, null, agentNo, null));
return ApiRes.ok();
}
@PreAuthorize("hasAnyAuthority('ENT_AGENT_INFO_EDIT', 'ENT_AGENT_INFO_VIEW')")
@GetMapping(value="/{agentNo}")
public ApiRes detail(@PathVariable("agentNo") String agentNo) {
AgentInfo agentInfo = agentInfoService.getById(agentNo);
if (agentInfo == null || !agentInfo.getPid().equals(getCurrentAgentNo())) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
return ApiRes.ok(agentInfo);
}
}

View File

@@ -0,0 +1,51 @@
package com.jeequan.jeepay.agent.ctrl.sysuser;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.utils.TreeDataBuilder;
import com.jeequan.jeepay.db.entity.SysEntitlement;
import com.jeequan.jeepay.service.impl.SysEntitlementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 权限菜单管理类
*
* @author terrfly
* @modify zhuxiao
*
* @date 2021-04-27 15:50
*/
@RestController
@RequestMapping("api/sysEnts")
public class SysEntController extends CommonCtrl {
@Autowired SysEntitlementService sysEntitlementService;
/** 查询权限集合 */
@PreAuthorize("hasAnyAuthority( 'ENT_UR_ROLE_ENT_LIST', 'ENT_UR_ROLE_DIST' )")
@RequestMapping(value="/showTree", method = RequestMethod.GET)
public ApiRes showTree() {
//查询全部数据
List<SysEntitlement> list = sysEntitlementService.list(SysEntitlement.gw().eq(SysEntitlement::getSysType, CS.SYS_ROLE_TYPE.AGENT));
//4. 转换为json树状结构
JSONArray jsonArray = (JSONArray) JSONArray.toJSON(list);
List<JSONObject> leftMenuTree = new TreeDataBuilder(jsonArray,
"entId", "pid", "children", "entSort", true)
.buildTreeObject();
return ApiRes.ok(leftMenuTree);
}
}

View File

@@ -0,0 +1,159 @@
package com.jeequan.jeepay.agent.ctrl.sysuser;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.agent.service.AuthService;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.utils.StringKit;
import com.jeequan.jeepay.db.entity.SysRole;
import com.jeequan.jeepay.db.entity.SysUserRoleRela;
import com.jeequan.jeepay.service.impl.SysRoleEntRelaService;
import com.jeequan.jeepay.service.impl.SysRoleService;
import com.jeequan.jeepay.service.impl.SysUserRoleRelaService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
* 角色管理类
*
* @author terrfly
* @modify zhuxiao
*
* @date 2021-04-27 15:50
*/
@RestController
@RequestMapping("api/sysRoles")
public class SysRoleController extends CommonCtrl {
@Autowired SysRoleService sysRoleService;
@Autowired SysUserRoleRelaService sysUserRoleRelaService;
@Autowired private AuthService authService;
@Autowired private SysRoleEntRelaService sysRoleEntRelaService;
/** list */
@PreAuthorize("hasAnyAuthority( 'ENT_UR_ROLE_LIST', 'ENT_UR_USER_UPD_ROLE' )")
@RequestMapping(value="", method = RequestMethod.GET)
public ApiRes list() {
SysRole queryObject = getObject(SysRole.class);
LambdaQueryWrapper<SysRole> condition = SysRole.gw();
condition.eq(SysRole::getSysType, CS.SYS_ROLE_TYPE.AGENT);
condition.eq(SysRole::getBelongInfoId, getCurrentAgentNo());
if(StringUtils.isNotEmpty(queryObject.getRoleName())){
condition.like(SysRole::getRoleName, queryObject.getRoleName());
}
if(StringUtils.isNotEmpty(queryObject.getRoleId())){
condition.like(SysRole::getRoleId, queryObject.getRoleId());
}
condition.orderByDesc(SysRole::getUpdatedAt); //时间倒序
IPage<SysRole> pages = sysRoleService.page(getIPage(true), condition);
return ApiRes.page(pages);
}
/** detail */
@PreAuthorize("hasAuthority( 'ENT_UR_ROLE_EDIT' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.GET)
public ApiRes detail(@PathVariable("recordId") String recordId) {
SysRole sysRole = sysRoleService.getOne(SysRole.gw().eq(SysRole::getRoleId, recordId).eq(SysRole::getBelongInfoId, getCurrentAgentNo()));
if (sysRole == null) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
return ApiRes.ok(sysRole);
}
/** add */
@PreAuthorize("hasAuthority( 'ENT_UR_ROLE_ADD' )")
@RequestMapping(value="", method = RequestMethod.POST)
public ApiRes add() {
SysRole SysRole = getObject(SysRole.class);
String roleId = "ROLE_" + StringKit.getUUID(6);
SysRole.setRoleId(roleId);
SysRole.setSysType(CS.SYS_ROLE_TYPE.AGENT); //后台系统
SysRole.setBelongInfoId(getCurrentUser().getSysUser().getBelongInfoId());
sysRoleService.save(SysRole);
//权限信息集合
String entIdListStr = getValString("entIdListStr");
//如果包含: 可分配权限的权限 && entIdListStr 不为空
if(getCurrentUser().getAuthorities().contains(new SimpleGrantedAuthority("ENT_UR_ROLE_DIST"))
&& StringUtils.isNotEmpty(entIdListStr)){
List<String> entIdList = JSONArray.parseArray(entIdListStr, String.class);
sysRoleEntRelaService.resetRela(roleId, entIdList);
}
return ApiRes.ok();
}
/** update */
@PreAuthorize("hasAuthority( 'ENT_UR_ROLE_EDIT' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.PUT)
public ApiRes update(@PathVariable("recordId") String recordId) {
SysRole sysRole = getObject(SysRole.class);
LambdaUpdateWrapper<SysRole> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(SysRole::getRoleId, recordId);
updateWrapper.eq(SysRole::getBelongInfoId, getCurrentAgentNo());
sysRoleService.update(sysRole, updateWrapper);
//权限信息集合
String entIdListStr = getValString("entIdListStr");
//如果包含: 可分配权限的权限 && entIdListStr 不为空
if(getCurrentUser().getAuthorities().contains(new SimpleGrantedAuthority("ENT_UR_ROLE_DIST"))
&& StringUtils.isNotEmpty(entIdListStr)){
List<String> entIdList = JSONArray.parseArray(entIdListStr, String.class);
sysRoleEntRelaService.resetRela(recordId, entIdList);
List<Long> sysUserIdList = new ArrayList<>();
sysUserRoleRelaService.list(SysUserRoleRela.gw().eq(SysUserRoleRela::getRoleId, recordId)).stream().forEach(item -> sysUserIdList.add(item.getUserId()));
//查询到该角色的人员, 将redis更新
authService.refAuthentication(sysUserIdList);
}
return ApiRes.ok();
}
/** delete */
@PreAuthorize("hasAuthority('ENT_UR_ROLE_DEL')")
@RequestMapping(value="/{recordId}", method = RequestMethod.DELETE)
public ApiRes del(@PathVariable("recordId") String recordId) {
SysRole sysRole = sysRoleService.getOne(SysRole.gw().eq(SysRole::getRoleId, recordId).eq(SysRole::getBelongInfoId, getCurrentAgentNo()));
if (sysRole == null) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
if(sysUserRoleRelaService.count(SysUserRoleRela.gw().eq(SysUserRoleRela::getRoleId, recordId)) > 0){
throw new BizException("当前角色已分配到用户, 不可删除!");
}
sysRoleService.removeRole(recordId);
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,85 @@
package com.jeequan.jeepay.agent.ctrl.sysuser;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.agent.service.AuthService;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.SysRole;
import com.jeequan.jeepay.db.entity.SysRoleEntRela;
import com.jeequan.jeepay.db.entity.SysUserRoleRela;
import com.jeequan.jeepay.service.impl.SysRoleEntRelaService;
import com.jeequan.jeepay.service.impl.SysRoleService;
import com.jeequan.jeepay.service.impl.SysUserRoleRelaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
* 角色权限管理类
*
* @author terrfly
* @modify zhuxiao
*
* @date 2021-04-27 15:50
*/
@RestController
@RequestMapping("api/sysRoleEntRelas")
public class SysRoleEntRelaController extends CommonCtrl {
@Autowired private SysRoleEntRelaService sysRoleEntRelaService;
@Autowired private SysUserRoleRelaService sysUserRoleRelaService;
@Autowired private SysRoleService sysRoleService;
@Autowired private AuthService authService;
/** list */
@PreAuthorize("hasAuthority( 'ENT_UR_ROLE_DIST' )")
@RequestMapping(value="", method = RequestMethod.GET)
public ApiRes list() {
SysRoleEntRela queryObject = getObject(SysRoleEntRela.class);
LambdaQueryWrapper<SysRoleEntRela> condition = SysRoleEntRela.gw();
if(queryObject.getRoleId() != null){
condition.eq(SysRoleEntRela::getRoleId, queryObject.getRoleId());
}
IPage<SysRoleEntRela> pages = sysRoleEntRelaService.page(getIPage(true), condition);
return ApiRes.page(pages);
}
/** 重置角色权限关联信息 */
@PreAuthorize("hasAuthority( 'ENT_UR_ROLE_DIST' )")
@RequestMapping(value="relas/{roleId}", method = RequestMethod.POST)
public ApiRes relas(@PathVariable("roleId") String roleId) {
SysRole sysRole = sysRoleService.getOne(SysRole.gw().eq(SysRole::getRoleId, roleId).eq(SysRole::getBelongInfoId, getCurrentAgentNo()));
if (sysRole == null) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
List<String> entIdList = JSONArray.parseArray(getValStringRequired("entIdListStr"), String.class);
sysRoleEntRelaService.resetRela(roleId, entIdList);
List<Long> sysUserIdList = new ArrayList<>();
sysUserRoleRelaService.list(SysUserRoleRela.gw().eq(SysUserRoleRela::getRoleId, roleId)).stream().forEach(item -> sysUserIdList.add(item.getUserId()));
//查询到该角色的人员, 将redis更新
authService.refAuthentication(sysUserIdList);
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,327 @@
package com.jeequan.jeepay.agent.ctrl.sysuser;
import cn.hutool.core.util.DesensitizedUtil;
import com.alibaba.fastjson.JSONObject;
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.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.agent.service.AuthService;
import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.cache.RedisUtil;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.jwt.JWTPayload;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.smsconfig.SmsBizDiyContentModel;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.SysUserAuth;
import com.jeequan.jeepay.db.entity.SysUserEntity;
import com.jeequan.jeepay.db.entity.SysUserTeam;
import com.jeequan.jeepay.service.impl.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
/**
* 用户管理类
*
* @author terrfly
* @modify zhuxiao
*
* @date 2021-04-27 15:50
*/
@RestController
@RequestMapping("api/sysUsers")
public class SysUserController extends CommonCtrl {
@Autowired SysUserService sysUserService;
@Autowired SysUserAuthService sysUserAuthService;
@Autowired SysConfigService sysConfigService;
@Autowired private AuthService authService;
@Autowired private SysUserTeamService sysUserTeamService;
@Autowired private AgentInfoService agentInfoService;
@Autowired private SmsManager smsManager;
/** list */
@PreAuthorize("hasAuthority( 'ENT_UR_USER_LIST' )")
@RequestMapping(value="", method = RequestMethod.GET)
public ApiRes list() {
SysUserEntity queryObject = getObject(SysUserEntity.class);
queryObject.setSysType(CS.SYS_ROLE_TYPE.AGENT);
queryObject.setBelongInfoId(getCurrentAgentNo());
// 是否app登录
String loginType = getCurrentUser().getLoginType();
boolean isApp = StringUtils.isNotBlank(loginType) && (loginType.equals(JWTPayload.LOGIN_PAGE_TYPE.APP) || loginType.equals(JWTPayload.LOGIN_PAGE_TYPE.LITE));
// true表示是APP端
if (isApp) {
String queryNameOrPhone = getValString("queryNameOrPhone"); // 名字或手机号模糊查询
LambdaQueryWrapper<SysUserEntity> queryWrapper = SysUserEntity.gw();
queryWrapper.eq(SysUserEntity::getSysType, queryObject.getSysType());
queryWrapper.eq(SysUserEntity::getBelongInfoId, queryObject.getBelongInfoId());
queryWrapper.eq(null != queryObject.getUserType(), SysUserEntity::getUserType, queryObject.getUserType());
if (StringUtils.isNotBlank(queryNameOrPhone)) {
queryWrapper.and(wr -> {
wr.like(SysUserEntity::getRealname, queryNameOrPhone)
.or().like(SysUserEntity::getTelphone, queryNameOrPhone);
});
}
IPage<SysUserEntity> iPage = sysUserService.page(getIPage(), queryWrapper);
// 数据脱敏
iPage.getRecords().stream().forEach(i -> i.setTelphone(DesensitizedUtil.mobilePhone(i.getTelphone())));
return ApiRes.page(iPage);
}
long count = sysUserService.queryCount(queryObject);
if (count <=0 ) {
return ApiRes.page(new Page());
}
List<JSONObject> list = sysUserService.selectList(getIPage(), queryObject);
// 邀请码二维码地址
String mchRegisterUrl = String.format("%s/register", sysConfigService.getDBApplicationConfig().getMchSiteUrl());
String agentRegisterUrl = String.format("%s/register", sysConfigService.getDBApplicationConfig().getAgentSiteUrl());
list.forEach(item -> {
item.put("inviteCodeUrl", String.format("%s?c=%s", mchRegisterUrl, item.getString("inviteCode")));
item.put("agentInviteCodeUrl", String.format("%s?c=%s", agentRegisterUrl, item.getString("inviteCode")));
// 数据脱敏
item.put("telphone", DesensitizedUtil.mobilePhone(item.getString("telphone")));
// 是否初始用户
boolean ifInitUser = agentInfoService.count(AgentInfo.gw().eq(AgentInfo::getInitUserId, item.getLong("sysUserId")).eq(AgentInfo::getAgentNo, item.getString("belongInfoId"))) >0;
item.put("initUser", ifInitUser);
});
return ApiRes.page(getIPage(), list, count);
}
/** detail */
@PreAuthorize("hasAuthority( 'ENT_UR_USER_VIEW' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.GET)
public ApiRes detail(@PathVariable("recordId") Integer recordId) {
SysUserEntity sysUserEntity = sysUserService.getById(recordId);
if (sysUserEntity == null) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
if (!sysUserEntity.getBelongInfoId().equals(getCurrentUser().getSysUser().getBelongInfoId())) {
throw new BizException(ApiCodeEnum.SYS_PERMISSION_ERROR);
}
if (sysUserEntity.getTeamId() != null) {
SysUserTeam sysUserTeam = sysUserTeamService.getById(sysUserEntity.getTeamId());
if (sysUserTeam != null) {
sysUserEntity.addExt("teamName", sysUserTeam.getTeamName());
}
}
return ApiRes.ok(sysUserEntity);
}
/** add */
@PreAuthorize("hasAuthority( 'ENT_UR_USER_ADD' )")
@RequestMapping(value="", method = RequestMethod.POST)
@MethodLog(remark = "添加管理员")
public ApiRes add() {
String loginPassword = getValString("loginPassword");
Byte isNotify = getValByteRequired("isNotify");
if (StringUtils.isBlank(loginPassword)) {
loginPassword = null;
}
SysUserEntity sysUserEntity = getObject(SysUserEntity.class);
sysUserEntity.setBelongInfoId(getCurrentUser().getSysUser().getBelongInfoId());
sysUserService.addSysUser(sysUserEntity, CS.SYS_ROLE_TYPE.AGENT, loginPassword);
// 发送短信通知
if (isNotify == CS.YES) {
smsManager.sendDiyContentSms(SmsBizDiyContentModel.genUserOpenAccount(sysUserEntity.getTelphone(), sysUserEntity.getLoginUsername(), loginPassword ));
}
return ApiRes.ok();
}
/** 修改操作员 登录认证信息 */
// @RequestMapping(value="/modifyPwd", method = RequestMethod.PUT)
public ApiRes authInfo() {
Long opSysUserId = getValLongRequired("recordId"); //操作员ID
//更改密码, 验证当前用户信息
String currentUserPwd = getValStringRequired("originalPwd"); //当前用户登录密码
//验证当前密码是否正确
if(!sysUserAuthService.validateCurrentUserPwd(currentUserPwd)){
throw new BizException("原密码验证失败!");
}
String opUserPwd = getValStringRequired("confirmPwd");
// 验证原密码与新密码是否相同
if (opUserPwd.equals(currentUserPwd)) {
throw new BizException("新密码与原密码相同!");
}
sysUserAuthService.resetAuthInfo(opSysUserId, null, null, true, opUserPwd, CS.SYS_ROLE_TYPE.AGENT);
return ApiRes.ok();
}
/** update */
@PreAuthorize("hasAuthority( 'ENT_UR_USER_EDIT' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.PUT)
@MethodLog(remark = "修改操作员信息")
public ApiRes update(@PathVariable("recordId") Long recordId) {
SysUserEntity sysUserEntity = getObject(SysUserEntity.class);
sysUserEntity.setSysUserId(recordId);
// 避免越权操作
SysUserEntity dbRecord = sysUserService.getOne(SysUserEntity.gw().eq(SysUserEntity::getSysUserId, recordId)
.eq(SysUserEntity::getSysType, CS.SYS_ROLE_TYPE.AGENT).eq(SysUserEntity::getBelongInfoId, getCurrentAgentNo()));
if (dbRecord == null) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
boolean delAuthenticationFlag = sysUserService.updateUserOnTx(sysUserEntity, recordId, getCurrentUser().getSysUserId());
// 删除用户redis缓存信息
if(delAuthenticationFlag){
authService.delAuthentication(Arrays.asList(recordId));
}
// 返回最新用户信息
SysUserEntity latestRecord = sysUserService.getById(recordId);
// 邀请码二维码地址
String mchRegisterUrl = String.format("%s/register", sysConfigService.getDBApplicationConfig().getMchSiteUrl());
latestRecord.addExt("inviteCodeUrl", String.format("%s?c=%s", mchRegisterUrl, latestRecord.getInviteCode()));
return ApiRes.ok(latestRecord);
}
/** delete */
@PreAuthorize("hasAuthority( 'ENT_UR_USER_DELETE' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.DELETE)
@MethodLog(remark = "删除操作员信息")
public ApiRes delete(@PathVariable("recordId") Long recordId) {
//查询该操作员信息
SysUserEntity sysUserEntity = sysUserService.getById(recordId);
if (sysUserEntity == null) {
throw new BizException("该操作员不存在!");
}
//判断是否自己删除自己
if(recordId.equals(getCurrentUser().getSysUser().getSysUserId())){
throw new BizException("系统不允许删除当前登陆用户!");
}
//判断是否删除商户默认超管
if(agentInfoService.count(AgentInfo.gw().eq(AgentInfo::getInitUserId, recordId).eq(AgentInfo::getAgentNo, sysUserEntity.getBelongInfoId())) > 0 ){
throw new BizException("系统不允许删除服务商默认用户!");
}
// 删除用户
sysUserService.removeUser(sysUserEntity, CS.SYS_ROLE_TYPE.AGENT);
//如果用户被删除需要更新redis数据
authService.refAuthentication(Arrays.asList(recordId));
return ApiRes.ok();
}
/** MFA验证 解绑 */
@PreAuthorize("hasAuthority( 'ENT_UR_USER_MFA_DELETE' )")
@RequestMapping(value="/mfaRelieve", method = RequestMethod.PUT)
@MethodLog(remark = "MFA验证解除")
public ApiRes mfaRelieve() throws BizException{
Long recordId = getValLongRequired("recordId");
// 当前登录账户是否为超管
Long currentUserId = getCurrentUser().getSysUser().getSysUserId();
// 解除操作员MFA验证
sysUserService.relieveOperatorMFA(currentUserId, recordId);
return ApiRes.ok();
}
/** 解除登录失败次数限制 */
@PreAuthorize("hasAuthority( 'ENT_UR_USER_LOGIN_LIMIT_DELETE' )")
@RequestMapping(value="/loginLimit/{recordId}", method = RequestMethod.DELETE)
@MethodLog(remark = "解除登录限制")
public ApiRes deleteLoginLimit(@PathVariable("recordId") Long recordId) throws BizException{
List<SysUserAuth> authList = sysUserAuthService.list(SysUserAuth.gw().eq(SysUserAuth::getUserId, recordId));
if (authList.isEmpty()) {
return ApiRes.ok();
}
for (SysUserAuth sysUserAuth : authList) {
RedisUtil.del(CS.getCacheKeyLoginErr(CS.SYS_ROLE_TYPE.AGENT, sysUserAuth.getIdentifier()));
}
return ApiRes.ok();
}
/** 提交审核 */
@RequestMapping(value="/audit", method = RequestMethod.PUT)
@MethodLog(remark = "提交审核")
public ApiRes audit() throws BizException{
// 提交的资料
AgentInfo agentInfo = getObject(AgentInfo.class);
// 查询数据库中的服务商信息
AgentInfo dbAgentInfo = agentInfoService.getById(getCurrentAgentNo());
if (dbAgentInfo == null) {
throw new BizException("服务商信息不存在!");
}
if (dbAgentInfo.getState() == CS.YES) {
throw new BizException("当前服务商已通过审核,不可修改信息!");
}
// 更新服务商资料
AgentInfo updateInfo = new AgentInfo();
updateInfo.setAgentNo(dbAgentInfo.getAgentNo());
updateInfo.setState(AgentInfo.AUDIT_STATE_ING);
updateInfo.setAgentName(agentInfo.getAgentName()); // 服务商名称
updateInfo.setAgentShortName(agentInfo.getAgentShortName()); // 服务商简称
updateInfo.setContactName(agentInfo.getContactName()); // 联系人姓名
updateInfo.setContactEmail(agentInfo.getContactEmail()); // 联系人邮箱
updateInfo.setLicenseImg(agentInfo.getLicenseImg()); // 营业执照
updateInfo.setIdcard1Img(agentInfo.getIdcard1Img()); // 身份证人像面
updateInfo.setIdcard2Img(agentInfo.getIdcard2Img()); // 身份证国徽面
updateInfo.setIdcardInHandImg(agentInfo.getIdcardInHandImg()); // 手持身份证照
updateInfo.setBankCardImg(agentInfo.getBankCardImg()); // 银行卡照片
updateInfo.setPermitImg(agentInfo.getPermitImg()); // 许可证照片
updateInfo.setAgentType(agentInfo.getAgentType()); // 服务商类型
updateInfo.setSettAccountType(agentInfo.getSettAccountType()); // 账户类型
updateInfo.setSettAccountNo(agentInfo.getSettAccountNo()); // 账户账号
updateInfo.setSettAccountName(agentInfo.getSettAccountName()); // 账户姓名
updateInfo.setSettAccountBank(agentInfo.getSettAccountBank()); // 银行名称
updateInfo.setSettAccountSubBank(agentInfo.getSettAccountSubBank()); // 开户行支行名称
agentInfoService.updateById(updateInfo);
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,78 @@
package com.jeequan.jeepay.agent.ctrl.sysuser;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.agent.service.AuthService;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.SysUserEntity;
import com.jeequan.jeepay.db.entity.SysUserRoleRela;
import com.jeequan.jeepay.service.impl.SysUserRoleRelaService;
import com.jeequan.jeepay.service.impl.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
/**
* 用户角色管理类
*
* @author terrfly
* @modify zhuxiao
*
* @date 2021-04-27 15:50
*/
@RestController
@RequestMapping("api/sysUserRoleRelas")
public class SysUserRoleRelaController extends CommonCtrl {
@Autowired private SysUserRoleRelaService sysUserRoleRelaService;
@Autowired private SysUserService sysUserService;
@Autowired private AuthService authService;
/** list */
@PreAuthorize("hasAuthority( 'ENT_UR_USER_UPD_ROLE' )")
@RequestMapping(value="", method = RequestMethod.GET)
public ApiRes list() {
SysUserRoleRela queryObject = getObject(SysUserRoleRela.class);
LambdaQueryWrapper<SysUserRoleRela> condition = SysUserRoleRela.gw();
if(queryObject.getUserId() != null){
condition.eq(SysUserRoleRela::getUserId, queryObject.getUserId());
}
IPage<SysUserRoleRela> pages = sysUserRoleRelaService.page(getIPage(true), condition);
return ApiRes.page(pages);
}
/** 重置用户角色关联信息 */
@PreAuthorize("hasAuthority( 'ENT_UR_USER_UPD_ROLE' )")
@RequestMapping(value="relas/{sysUserId}", method = RequestMethod.POST)
public ApiRes relas(@PathVariable("sysUserId") Long sysUserId) {
SysUserEntity dbRecord = sysUserService.getOne(SysUserEntity.gw().eq(SysUserEntity::getSysUserId, sysUserId).eq(SysUserEntity::getBelongInfoId, getCurrentAgentNo()));
if (dbRecord == null) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
}
List<String> roleIdList = JSONArray.parseArray(getValStringRequired("roleIdListStr"), String.class);
sysUserService.saveUserRole(sysUserId, roleIdList);
authService.refAuthentication(Arrays.asList(sysUserId));
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,232 @@
package com.jeequan.jeepay.agent.ctrl.sysuser;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.jwt.JWTPayload;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.utils.DateKit;
import com.jeequan.jeepay.db.entity.SysUserEntity;
import com.jeequan.jeepay.db.entity.SysUserTeam;
import com.jeequan.jeepay.service.impl.SysUserService;
import com.jeequan.jeepay.service.impl.SysUserTeamService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
/**
* 操作员列表
*
* @author zx
*
* @date 2022/3/17 17:13
*/
@RestController
@RequestMapping("/api/userTeams")
public class SysUserTeamController extends CommonCtrl {
@Autowired private SysUserTeamService sysUserTeamService;
@Autowired private SysUserService sysUserService;
/** list */
@PreAuthorize("hasAuthority( 'ENT_UR_TEAM_LIST' )")
@RequestMapping(value="", method = RequestMethod.GET)
public ApiRes list() {
// 是否app登录
String loginType = getCurrentUser().getLoginType();
boolean isApp = StringUtils.isNotBlank(loginType) && (loginType.equals(JWTPayload.LOGIN_PAGE_TYPE.APP) || loginType.equals(JWTPayload.LOGIN_PAGE_TYPE.LITE));
SysUserTeam queryObject = getObject(SysUserTeam.class);
queryObject.setSysType(CS.SYS_ROLE_TYPE.AGENT);
queryObject.setBelongInfoId(getCurrentAgentNo());
// 团队列表
IPage<SysUserTeam> iPage = sysUserTeamService.selectPage(getIPage(true), queryObject);
// 1、查询全部团队列表直接返回
int pageSize = getValIntegerRequired("pageSize");
if (pageSize == -1) {
return ApiRes.page(iPage);
}
// 2、web端仅返回团队列表
if (!isApp) {
return ApiRes.page(iPage);
}
if (iPage.getTotal() <= 0) {
return ApiRes.page(new Page());
}
// 3、app端返回团队列表 包含团队成员信息
// 当前分页团队ID集合
List<Long> teamIdList = new LinkedList<>();
iPage.getRecords().forEach(record -> teamIdList.add(record.getTeamId()));
// 查询团队id下的用户
List<JSONObject> list = sysUserTeamService.selectList(teamIdList, null, null);
if (CollUtil.isEmpty(list)) {
return ApiRes.page(iPage);
}
// 外层:循环团队 内层:团队成员数据
for (SysUserTeam sysUserTeam : iPage.getRecords()) {
// 用户列表
List<JSONObject> userList = new LinkedList<>();
// 团队总商户数
Long totalMchCount = 0L;
// 团队总交易额
Long totalOrderAmount = 0L;
for (JSONObject json : list) {
if (sysUserTeam.getTeamId().equals(json.getLong("teamId"))) {
userList.add(json);
if (json.getLong("mchCount") != null) {
totalMchCount += json.getLong("mchCount");
}
if (json.getLong("orderAmount") != null) {
totalOrderAmount += json.getLong("orderAmount");
}
}
}
sysUserTeam.addExt("userList", userList);
sysUserTeam.addExt("totalMchCount", totalMchCount);
sysUserTeam.addExt("totalOrderAmount", totalOrderAmount);
}
return ApiRes.page(iPage);
}
/** web端 团队详情下的拓展员信息 */
@PreAuthorize("hasAuthority( 'ENT_UR_USER_VIEW' )")
@RequestMapping(value="/userList/{recordId}", method = RequestMethod.GET)
public ApiRes userList(@PathVariable("recordId") Long recordId) {
IPage<SysUserEntity> iPage = sysUserService.page(getIPage(), SysUserEntity.gw().eq(SysUserEntity::getTeamId, recordId));
if (iPage.getTotal() <= 0) {
return ApiRes.page(new Page());
}
// 查询团队id下的用户
String dateRange = getValStringRequired("queryDateRange");
// 获取查询时间请求参数 [开始时间, 结束时间]
Date[] queryDateRangeArray = DateKit.getQueryDateRange(dateRange);
String createdStart = DateUtil.formatDateTime(queryDateRangeArray[0]);
String createdEnd = DateUtil.formatDateTime(queryDateRangeArray[1]);
List<JSONObject> list = sysUserTeamService.selectList(Arrays.asList(recordId), createdStart, createdEnd);
if (CollUtil.isEmpty(list)) {
return ApiRes.page(iPage);
}
// 用户列表
List<JSONObject> userList = new LinkedList<>();
for (SysUserEntity sysUserEntity : iPage.getRecords()) {
for (JSONObject json : list) {
if (sysUserEntity.getSysUserId().equals(json.getLong("sysUserId"))) {
userList.add(json);
}
}
}
return ApiRes.page(getIPage(), userList, iPage.getTotal());
}
/** detail */
@PreAuthorize("hasAuthority( 'ENT_UR_USER_EDIT' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.GET)
public ApiRes detail(@PathVariable("recordId") Integer recordId) {
return ApiRes.ok(sysUserTeamService.getById(recordId));
}
/** add */
@PreAuthorize("hasAuthority( 'ENT_UR_TEAM_ADD' )")
@MethodLog(remark = "添加团队")
@RequestMapping(value="", method = RequestMethod.POST)
public ApiRes add() {
SysUserTeam sysUserTeam = getObject(SysUserTeam.class);
sysUserTeam.setSysType(CS.SYS_ROLE_TYPE.AGENT);
sysUserTeam.setBelongInfoId(getCurrentAgentNo());
long count = sysUserTeamService.count(SysUserTeam.gw().eq(SysUserTeam::getTeamName, sysUserTeam.getTeamName()));
if (count > 0) {
throw new BizException("团队名已存在");
}
boolean result = sysUserTeamService.save(sysUserTeam);
if (!result) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_CREATE);
}
return ApiRes.ok();
}
/** update */
@PreAuthorize("hasAuthority( 'ENT_UR_TEAM_EDIT' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.PUT)
@MethodLog(remark = "修改团队信息")
public ApiRes update(@PathVariable("recordId") Long recordId) {
SysUserTeam sysUserTeam = getObject(SysUserTeam.class);
sysUserTeam.setTeamId(recordId);
long count = sysUserTeamService.count(SysUserTeam.gw()
.eq(SysUserTeam::getTeamName, sysUserTeam.getTeamName())
.ne(SysUserTeam::getTeamId, recordId)
);
if (count > 0) {
throw new BizException("团队名已存在");
}
boolean result = sysUserTeamService.updateById(sysUserTeam);
if (!result) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
}
return ApiRes.ok();
}
/** delete */
@PreAuthorize("hasAuthority( 'ENT_UR_TEAM_DELETE' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.DELETE)
@MethodLog(remark = "删除团队")
public ApiRes delete(@PathVariable("recordId") Long recordId) {
// 删除团队
boolean result = sysUserTeamService.removeById(recordId);
if (!result) {
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_DELETE);
}
return ApiRes.ok();
}
}

View File

@@ -0,0 +1,40 @@
package com.jeequan.jeepay.agent.ctrl.transfer;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.agent.websocket.server.WsChannelUserIdServer;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 获取用户ID - 回调函数
*
* @author terrfly
*
* @date 2021/8/13 17:54
*/
@Controller
@RequestMapping("/api/anon/channelUserIdCallback")
public class ChannelUserIdNotifyController extends CommonCtrl {
@RequestMapping("")
public String channelUserIdCallback() {
try {
//请求参数
JSONObject params = getReqParamJSON();
String extParam = params.getString("extParam");
String channelUserId = params.getString("channelUserId");
String appId = params.getString("appId");
//推送到前端
WsChannelUserIdServer.sendMsgByAppAndCid(appId, extParam, channelUserId);
} catch (Exception e) {
request.setAttribute("errMsg", e.getMessage());
}
return "channelUser/getChannelUserIdPage";
}
}

View File

@@ -0,0 +1,105 @@
package com.jeequan.jeepay.agent.ctrl.transfer;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.IsvUserConn;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.RateConfig;
import com.jeequan.jeepay.db.entity.TransferInterfaceDefineEntity;
import com.jeequan.jeepay.service.impl.IsvInfoService;
import com.jeequan.jeepay.service.impl.TransferInterfaceDefineService;
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 java.util.*;
/**
* TODO
*
* @author deng
* @since 2024/4/25
*/
@RestController
@RequestMapping("api/transferConfig")
public class TransferConfigController extends CommonCtrl {
@Autowired
private TransferInterfaceDefineService transferInterfaceDefineService;
@Autowired
private IsvInfoService isvInfoService;
/**
* 查询可用的支付接口
* <p>
* 使用功能项目: 参数及费率的填写
* 服务商查询全部支付接口
* 服务商查询服务商开启的支付接口
**/
@GetMapping("/ifCodes")
public ApiRes ifCodes() {
// 搜索条件
String ifName = getValString("ifName");
String infoId = getValStringRequired("infoId"); // infoId
String configMode = getValStringRequired("configMode"); // 设置类型
// 支付接口列表
LambdaQueryWrapper<TransferInterfaceDefineEntity> lambdaQueryWrapper = Wrappers.lambdaQuery();
lambdaQueryWrapper.eq(TransferInterfaceDefineEntity::getState, CS.YES); // 查询可用的支付接口列表
lambdaQueryWrapper.like(ObjUtil.isNotEmpty(ifName), TransferInterfaceDefineEntity::getTransIfName, ifName);
AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());
Map<String, IsvUserConn> ifCodeMap = new HashMap<>();
// 服务商 配置 商户费率 | 下级服务商费率 | 自己配置信息 【显示 当前服务商所有接口】
if (RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode) ||
RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode) ||
RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)
) {
ifCodeMap = isvInfoService.getTransIsvUserConn(CS.SYS_ROLE_TYPE.AGENT, agentInfo.getAgentNo(), CS.YES);
List<String> ifCodeList = new ArrayList<>(ifCodeMap.keySet());
if (ifCodeList.isEmpty()) { // 没有可用的接口
return ApiRes.ok(ifCodeList);
}
lambdaQueryWrapper.in(TransferInterfaceDefineEntity::getTransIfCode, ifCodeList);
} else if (RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode)) { // 服务商进件
// 查询 当前服务商 开通的
ifCodeMap = isvInfoService.getTransIsvUserConn(CS.SYS_ROLE_TYPE.AGENT, agentInfo.getAgentNo(), null);
if (ifCodeMap.isEmpty()) { // 没有可用的接口
return ApiRes.ok(Collections.emptyList());
}
lambdaQueryWrapper.in(TransferInterfaceDefineEntity::getTransIfCode, ifCodeMap.keySet());
}
final List<TransferInterfaceDefineEntity> list = new ArrayList<>();
lambdaQueryWrapper.orderByAsc(TransferInterfaceDefineEntity::getId);
final Map<String, IsvUserConn> finalMap = ifCodeMap;
transferInterfaceDefineService.list(lambdaQueryWrapper).forEach(item -> {
// 如果服务商上级配置的开启进件为关闭,那么最终展示的列表中显示的是否开启进件也为关闭
IsvUserConn ifCodeInfo = finalMap.get(item.getTransIfCode());
boolean isEnabled = ifCodeInfo.getStatus() == CS.YES && ifCodeInfo.getConfigStatus() == CS.YES;
item.addExt("configState", ifCodeInfo.getStatus());
item.setState(isEnabled ? CS.YES : CS.NO);
list.add(item);
});
return ApiRes.ok(list);
}
}

View File

@@ -0,0 +1,69 @@
package com.jeequan.jeepay.agent.mq;
import com.jeequan.jeepay.components.mq.model.CleanAgentLoginAuthCacheMQ;
import com.jeequan.jeepay.core.cache.RedisUtil;
import com.jeequan.jeepay.core.constants.CS;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.List;
/**
* 接收MQ消息
* 业务: 清除服务商的登录信息
* @author terrfly
* @date 2021/7/27 9:23
*/
@Slf4j
@Component
public class CleanAgentLoginAuthCacheMQReceiver implements CleanAgentLoginAuthCacheMQ.IMQReceiver {
@Override
public void receive(CleanAgentLoginAuthCacheMQ.MsgPayload payload) {
log.info("成功接收删除商户用户登录的订阅通知, msg={}", payload);
if (CleanAgentLoginAuthCacheMQ.CLEAN_CACHE_TYPE_LOGIN_TOKEN.equals(payload.getCleanCacheType())) {
// 字符串转List<String>
List<String> userIdList = payload.getList();
// 删除redis用户缓存
if(userIdList == null || userIdList.isEmpty()){
log.info("用户ID为空");
return ;
}
for (String sysUserId : userIdList) {
Collection<String> cacheKeyList = RedisUtil.keys(CS.getCacheKeyToken(Long.valueOf(sysUserId), "*"));
if(cacheKeyList == null || cacheKeyList.isEmpty()){
continue;
}
for (String cacheKey : cacheKeyList) {
// 删除用户Redis信息
RedisUtil.del(cacheKey);
continue;
}
}
log.info("无权限登录用户信息已清除");
}
// 清除登录失败次数限制缓存
else if (CleanAgentLoginAuthCacheMQ.CLEAN_CACHE_TYPE_LOGIN_ERR.equals(payload.getCleanCacheType())) {
// 字符串转List<String>
List<String> list = payload.getList();
// 删除redis用户缓存
if(CollectionUtils.isEmpty(list)){
log.info("登录用户名list为空");
return ;
}
for (String loginUserName : list) {
RedisUtil.del(CS.getCacheKeyLoginErr(CS.SYS_ROLE_TYPE.AGENT, loginUserName));
}
log.info("登录限制已清除");
}
}
}

View File

@@ -0,0 +1,37 @@
package com.jeequan.jeepay.agent.mq;
import com.jeequan.jeepay.components.mq.model.ResetAppConfigMQ;
import com.jeequan.jeepay.core.interfaces.push.IBaiduBceService;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.service.impl.SysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 接收MQ消息
* 业务: 更新系统配置参数
* @author terrfly
* @date 2021/7/27 9:23
*/
@Slf4j
@Component
public class ResetAppConfigMQReceiver implements ResetAppConfigMQ.IMQReceiver {
@Autowired
private SysConfigService sysConfigService;
@Override
public void receive(ResetAppConfigMQ.MsgPayload payload) {
log.info("成功接收更新系统配置的订阅通知, msg={}", payload);
sysConfigService.initDBConfig(payload.getGroupKey());
// 修改百度语音配置需清空redis缓存的百度token
if (SysConfigService.BAIDU_BCE_CONFIG.getLeft().equals(payload.getGroupKey())) {
IBaiduBceService baiduBceService = SpringBeansUtil.getBean("baiduBceService", IBaiduBceService.class);
baiduBceService.clearBaiduBceTokenCache(SysConfigService.BAIDU_BCE_CONFIG.getRight());
}
log.info("系统配置静态属性已重置");
}
}

View File

@@ -0,0 +1,61 @@
package com.jeequan.jeepay.agent.mq;
import com.jeequan.jeepay.components.mq.model.ResetIsvMchAppInfoConfigMQ;
import com.jeequan.jeepay.core.interfaces.IConfigContextService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 接收MQ消息
* 业务: 更新服务商/商户/商户应用配置信息;
*
* @author terrfly
* @date 2021/7/27 9:23
*/
@Slf4j
@Component
public class ResetIsvMchAppInfoMQReceiver implements ResetIsvMchAppInfoConfigMQ.IMQReceiver {
@Autowired(required = false)
private IConfigContextService configContextService;
@Override
public void receive(ResetIsvMchAppInfoConfigMQ.MsgPayload payload) {
if (payload.getResetType() == ResetIsvMchAppInfoConfigMQ.RESET_TYPE_ISV_INFO) {
this.modifyIsvInfo(payload.getIsvNo());
} else if (payload.getResetType() == ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_INFO) {
this.modifyMchInfo(payload.getMchNo());
}
}
/**
* 接收 [商户配置信息] 的消息
*/
private void modifyMchInfo(String mchNo) {
log.info("成功接收 [商户配置信息] 的消息, msg={}", mchNo);
if (configContextService != null) configContextService.initMchInfoConfigContext(mchNo);
log.info(" [商户配置信息] 已重置");
}
/**
* 接收 [商户应用支付参数配置信息] 的消息
*/
private void modifyMchApp(String mchNo, String appId) {
log.info("成功接收 [商户应用支付参数配置信息] 的消息, mchNo={}, appId={}", mchNo, appId);
if (configContextService != null) configContextService.initMchAppConfigContext(mchNo, appId);
log.info(" [商户应用支付参数配置信息] 已重置");
}
/**
* 重置ISV信息
*/
private void modifyIsvInfo(String isvNo) {
log.info("成功接收 [ISV信息] 重置, msg={}", isvNo);
if (configContextService != null) configContextService.initIsvConfigContext(isvNo);
log.info("[ISV信息] 已重置");
}
}

View File

@@ -0,0 +1,38 @@
package com.jeequan.jeepay.agent.secruity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;
/*
* 用户身份认证失败处理类
*
* @author terrfly
*
* @date 2021/6/8 17:11
*/
@Component
public class JeeAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
// This is invoked when user tries to access a secured REST resource without supplying any credentials
// We should just send a 401 Unauthorized response because there is no 'login page' to redirect to
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
//返回json形式的错误信息
// response.setCharacterEncoding("UTF-8");
// response.setContentType("application/json");
// response.getWriter().println("{\"code\":1001, \"msg\":\"Unauthorized\"}");
response.getWriter().flush();
}
}

View File

@@ -0,0 +1,107 @@
package com.jeequan.jeepay.agent.secruity;
import com.jeequan.jeepay.agent.config.SystemYmlConfig;
import com.jeequan.jeepay.agent.service.AuthService;
import com.jeequan.jeepay.bizcommons.manage.auth.AuthManage;
import com.jeequan.jeepay.core.cache.ITokenService;
import com.jeequan.jeepay.core.cache.RedisUtil;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.jwt.JWTPayload;
import com.jeequan.jeepay.core.jwt.JWTUtils;
import com.jeequan.jeepay.core.model.security.JeeUserDetails;
import com.jeequan.jeepay.core.utils.DateKit;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* <p><b>Title: </b>JwtAuthenticationTokenFilter.java
* <p><b>Description: </b>
* spring security框架中验证组件的前置过滤器
* 用于验证token有效期并放置ContextAuthentication信息,为后续spring security框架验证提供数据
* 避免使用@Component等bean自动装配注解@Component会将filter被spring实例化为web容器的全局filter导致重复过滤。
* @modify terrfly
* @version V1.0
*
* @date 2021-04-27 15:50
* <p>
*/
public class JeeAuthenticationTokenFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
JeeUserDetails jeeUserDetails = commonFilter(request);
if(jeeUserDetails == null){
chain.doFilter(request, response);
return;
}
// 密码是否过期
if(AuthManage.passwordExpiredFilter(jeeUserDetails, request, response)){
return ;
}
// 服务商是否过审
if(AuthManage.agentUnAuditFilter(jeeUserDetails, request, response)){
return ;
}
//将信息放置到Spring-security context中
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(jeeUserDetails, null, jeeUserDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
}
private JeeUserDetails commonFilter(HttpServletRequest request){
String authToken = request.getHeader(CS.ACCESS_TOKEN_NAME);
if(StringUtils.isEmpty(authToken)){
authToken = request.getParameter(CS.ACCESS_TOKEN_NAME);
}
if(StringUtils.isEmpty(authToken)){
return null; //放行,并交给UsernamePasswordAuthenticationFilter进行验证,返回公共错误信息.
}
JWTPayload jwtPayload = JWTUtils.parseToken(authToken, SpringBeansUtil.getBean(SystemYmlConfig.class).getJwtSecret()); //反解析token信息
//token字符串解析失败
if( jwtPayload == null || StringUtils.isEmpty(jwtPayload.getCacheKey())) {
return null;
}
//根据用户名查找数据库
JeeUserDetails jwtBaseUser = RedisUtil.getObject(jwtPayload.getCacheKey(), JeeUserDetails.class);
if(jwtBaseUser == null){ // 找不到对应的缓存
// app登录 有效期30天 超时自动续期
if(jwtPayload.isAppLogin() && DateKit.currentTimeMillis() - jwtPayload.getCreated() <= (CS.TOKEN_TIME_APP * 1000) ){
SpringBeansUtil.getBean(AuthService.class).authBySysUserId(jwtPayload.getSysUserId(), jwtPayload.getLoginType(), jwtPayload.getCacheKey());
return RedisUtil.getObject(jwtPayload.getCacheKey(), JeeUserDetails.class);
}
// 其他情况,需要删除
RedisUtil.del(jwtPayload.getCacheKey());
return null; //数据库查询失败删除redis
}
//续签时间
RedisUtil.expire(jwtPayload.getCacheKey(), ITokenService.getTokenCacheTime(jwtPayload.getLoginType()));
return jwtBaseUser;
}
}

View File

@@ -0,0 +1,86 @@
package com.jeequan.jeepay.agent.secruity;
import com.jeequan.jeepay.converter.BaseConverter;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.JeepayAuthenticationException;
import com.jeequan.jeepay.core.model.security.JeeUserDetails;
import com.jeequan.jeepay.core.utils.RegKit;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.SysUserAuth;
import com.jeequan.jeepay.db.entity.SysUserEntity;
import com.jeequan.jeepay.service.impl.AgentInfoService;
import com.jeequan.jeepay.service.impl.SysUserAuthService;
import com.jeequan.jeepay.service.impl.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
/**
* UserDetailsService实现类
*
* @author terrfly
* @modify zhuxiao
*
* @date 2021-04-27 15:50
*/
@Service
public class JeeUserDetailsServiceImpl implements UserDetailsService {
@Autowired
private SysUserService sysUserService;
@Autowired
private SysUserAuthService sysUserAuthService;
@Autowired AgentInfoService agentInfoService;
@Autowired private BaseConverter baseConverter;
/**
*
* 此函数为: authenticationManager.authenticate(upToken) 内部调用 ;
* 需返回 用户信息载体 / 用户密码 。
* 用户角色+权限的封装集合 (暂时不查询, 在验证通过后再次查询,避免用户名密码输入有误导致查询资源浪费)
*
* **/
@Override
public UserDetails loadUserByUsername(String loginUsernameStr) throws UsernameNotFoundException {
//登录方式, 默认为账号密码登录
byte identityType = CS.AUTH_TYPE.LOGIN_USER_NAME;
if(RegKit.isMobile(loginUsernameStr)){
identityType = CS.AUTH_TYPE.TELPHONE; //手机号登录
}
//首先根据登录类型 + 用户名得到 信息
SysUserAuth auth = sysUserAuthService.selectByLogin(loginUsernameStr, identityType, CS.SYS_ROLE_TYPE.AGENT);
// SysUserAuth auth = sysUserAuthService.getUserByLogin(loginUsernameStr, identityType);
if(auth == null){ //没有该用户信息
throw JeepayAuthenticationException.build("用户名/密码错误!");
}
//用户ID
Long userId = auth.getUserId();
SysUserEntity sysUserEntity = sysUserService.getById(userId);
if (sysUserEntity == null) {
throw JeepayAuthenticationException.build("用户名/密码错误!");
}
if(CS.PUB_USABLE != sysUserEntity.getState()){ //状态不合法
throw JeepayAuthenticationException.build("用户状态不可登录,请联系管理员!");
}
AgentInfo agentInfo = agentInfoService.getById(sysUserEntity.getBelongInfoId());
if (agentInfo == null) {
throw JeepayAuthenticationException.build("服务商信息不存在!");
}
return new JeeUserDetails(baseConverter.toModel(sysUserEntity), auth.getCredential(), agentInfo.getState());
}
}

View File

@@ -0,0 +1,136 @@
package com.jeequan.jeepay.agent.secruity;
import com.jeequan.jeepay.agent.config.SystemYmlConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/*
* Spring Security 配置项
*
* @author terrfly
*
* @date 2021/6/8 17:11
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //开启@PreAuthorize @PostAuthorize 等前置后置安全校验注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired private UserDetailsService userDetailsService;
@Autowired private JeeAuthenticationEntryPoint unauthorizedHandler;
@Autowired private SystemYmlConfig systemYmlConfig;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 使用BCrypt强哈希函数 实现PasswordEncoder
* **/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(this.userDetailsService)
.passwordEncoder(passwordEncoder());
}
/** 允许跨域请求 **/
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
if(systemYmlConfig.getAllowCors()){
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); //带上cookie信息
// config.addAllowedOrigin(CorsConfiguration.ALL); //允许跨域的域名, *表示允许任何域名使用
config.addAllowedOriginPattern(CorsConfiguration.ALL); //使用addAllowedOriginPattern 避免出现 When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
config.addAllowedHeader(CorsConfiguration.ALL); //允许任何请求头
config.addAllowedMethod(CorsConfiguration.ALL); //允许任何方法post、get等
source.registerCorsConfiguration("/**", config); // CORS 配置对所有接口都有效
}
return new CorsFilter(source);
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// 由于使用的是JWT我们这里不需要csrf
.csrf().disable()
.cors().and()
// 认证失败处理方式
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// 基于token所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();
// 添加JWT filter
httpSecurity.addFilterBefore(new JeeAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
// 禁用缓存
httpSecurity.headers().cacheControl();
}
@Override
public void configure(WebSecurity web) throws Exception {
//ignore文件 无需进入spring security 框架
// 1.允许对于网站静态资源的无授权访问
// 2.对于获取token的rest api要允许匿名访问
web.ignoring().antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/**/*.png",
"/**/*.jpg",
"/**/*.jpeg",
"/**/*.svg",
"/**/*.ico",
"/**/*.webp",
"/*.txt",
"/**/*.xls",
"/**/*.mp4" //支持mp4格式的文件匿名访问
)
.antMatchers(
"/api/anon/**", //匿名访问接口
"/api/pos/**", //匿名访问接口pos机设备
"/api/advert/appAdvert/**" //匿名访问接口,广告接口
);
}
}

View File

@@ -0,0 +1,362 @@
package com.jeequan.jeepay.agent.service;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.agent.config.SystemYmlConfig;
import com.jeequan.jeepay.bizcommons.manage.auth.AuthManage;
import com.jeequan.jeepay.converter.BaseConverter;
import com.jeequan.jeepay.core.cache.ITokenService;
import com.jeequan.jeepay.core.cache.RedisUtil;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.SysUser;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.exception.JeepayAuthenticationException;
import com.jeequan.jeepay.core.jwt.JWTPayload;
import com.jeequan.jeepay.core.jwt.JWTUtils;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.security.JeeUserDetails;
import com.jeequan.jeepay.core.utils.JsonKit;
import com.jeequan.jeepay.db.entity.AgentConfig;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.SysUserEntity;
import com.jeequan.jeepay.service.impl.*;
import com.jeequan.jeepay.service.mapper.SysEntitlementMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
/**
* 认证Service
*
* @modify zhuxiao
*
* @date 2021-04-27 15:50
*/
@Slf4j
@Service
public class AuthService {
@Resource
private AuthenticationManager authenticationManager;
@Autowired
private SysUserService sysUserService;
@Autowired
private SysRoleService sysRoleService;
@Autowired
private SysRoleEntRelaService sysRoleEntRelaService;
@Autowired
private AgentInfoService agentInfoService;
@Autowired
private SysEntitlementMapper sysEntitlementMapper;
@Autowired
private SystemYmlConfig systemYmlConfig;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private AuthManage authManage;
@Autowired
private BaseConverter baseConverter;
@Autowired private AgentConfigService agentConfigService;
/**
* 登录认证(密码登录, 包含MFA二次认证校验)
**/
public ApiRes authByAuthentication(String username, String password, String loginType, String vercodeToken, String mfaCode) {
// 防穷举判断
authManage.loginErrValidate(CS.SYS_ROLE_TYPE.AGENT, username);
//1. 生成spring-security usernamePassword类型对象
UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password);
//spring-security 自动认证过程;
// 1. 进入 JeeUserDetailsServiceImpl.loadUserByUsername 获取用户基本信息;
//2. SS根据UserDetails接口验证是否用户可用
//3. 最后返回loadUserByUsername 封装的对象信息;
Authentication authentication = null;
try {
authentication = authenticationManager.authenticate(upToken);
} catch (JeepayAuthenticationException jex) {
throw jex.getBizException() == null ? new BizException(jex.getMessage()) : jex.getBizException();
} catch (BadCredentialsException e) {
// 防穷举累加
authManage.loginErrCount(CS.SYS_ROLE_TYPE.AGENT, username);
// throw new BizException("用户名/密码错误!");
} catch (AuthenticationException e) {
log.error("AuthenticationException:", e);
throw new BizException("认证服务出现异常, 请重试或联系系统管理员!");
}
JeeUserDetails jeeUserDetails = (JeeUserDetails) authentication.getPrincipal();
SysUser sysUser = jeeUserDetails.getSysUser();
// 第一次登录 && 该用户是否已经绑定MFA验证 : 返回前端需要MFA的二次认证
if (StringUtils.isEmpty(mfaCode) && sysUser.getMfaBindState() == CS.YES) {
return ApiRes.ok4newJson("isMFA", true);
}
// mfaCode != null 说明: 二次输入的验证, 需要验证MFA验证码
if (StringUtils.isNotEmpty(mfaCode)) {
sysUserService.checkMFACode(sysUser.getSysUserId(), mfaCode);
}
// 删除图形验证码缓存数据 & 返回accessToken
RedisUtil.del(CS.getCacheKeyImgCode(vercodeToken));
String accessToken = userDetailsProcess(jeeUserDetails, loginType, null, JWTPayload.CREDENTIAL_AUTH_TYPE.PASSWD);
// 更新上次登录时间
sysUserService.updateLastLoginTime(sysUser.getSysUserId());
JSONObject tokenRes = JsonKit.newJson(CS.ACCESS_TOKEN_NAME, accessToken);
tokenRes.put("lastLoginTime", jeeUserDetails.getSysUser().getLastLoginTime());
AgentInfo agentInfo = agentInfoService.getById(sysUser.getUserNo());
List<String> agentNoList = new ArrayList<>();
Optional.ofNullable(agentInfo.getPidArr()).ifPresent(item -> {
agentNoList.addAll(Arrays.asList(item.split(",")));
});
agentNoList.add(agentInfo.getAgentNo());
List<AgentConfig> list = agentConfigService.lambdaQuery()
.in(AgentConfig::getAgentNo, agentNoList)
.eq(AgentConfig::getGroupKey, "agentSiteConfig")
.eq(AgentConfig::getConfigKey, "agentSiteUrl")
.list();
if (!list.isEmpty()) {
tokenRes.put("oemSiteUrl", list.get(0).getConfigVal());
}
return ApiRes.ok(tokenRes);
}
/**
* 认证(手机验证码方式)
*/
public ApiRes authByPhoneCode(String phone, String loginType) {
JeeUserDetails jeeUserDetails = (JeeUserDetails) userDetailsService.loadUserByUsername(phone);
String accessToken = userDetailsProcess(jeeUserDetails, loginType, null, JWTPayload.CREDENTIAL_AUTH_TYPE.TEL_CODE);
// 更新上次登录时间
sysUserService.updateLastLoginTime(jeeUserDetails.getSysUserId());
JSONObject tokenRes = JsonKit.newJson(CS.ACCESS_TOKEN_NAME, accessToken);
tokenRes.put("lastLoginTime", jeeUserDetails.getSysUser().getLastLoginTime());
AgentInfo agentInfo = agentInfoService.getById(jeeUserDetails.getSysUser().getUserNo());
List<String> agentNoList = new ArrayList<>();
Optional.ofNullable(agentInfo.getPidArr()).ifPresent(item -> {
agentNoList.addAll(Arrays.asList(item.split(",")));
});
agentNoList.add(agentInfo.getAgentNo());
List<AgentConfig> list = agentConfigService.lambdaQuery()
.in(AgentConfig::getAgentNo, agentNoList)
.eq(AgentConfig::getGroupKey, "agentSiteConfig")
.eq(AgentConfig::getConfigKey, "agentSiteUrl")
.list();
if (!list.isEmpty()) {
tokenRes.put("oemSiteUrl", list.get(0).getConfigVal());
}
return ApiRes.ok(tokenRes);
}
/**
* 认证app扫码登录方式
*/
public JSONObject authByAppQrcode(Long sysUserId, String loginType) {
SysUserEntity sysUser = sysUserService.getById(sysUserId);
if (sysUser == null || sysUser.getState() != CS.YES) {
throw new BizException("用户不存在或状态不可用");
}
String accessToken = userDetailsProcess(userDetailsService.loadUserByUsername(sysUser.getLoginUsername()), loginType, null, JWTPayload.CREDENTIAL_AUTH_TYPE.QR_CODE);
// 更新上次登录时间
sysUserService.updateLastLoginTime(sysUserId);
JSONObject tokenRes = JsonKit.newJson(CS.ACCESS_TOKEN_NAME, accessToken);
tokenRes.put("lastLoginTime", sysUser.getLastLoginTime());
AgentInfo agentInfo = agentInfoService.getById(sysUser.getUserNo());
List<String> agentNoList = new ArrayList<>();
Optional.ofNullable(agentInfo.getPidArr()).ifPresent(item -> {
agentNoList.addAll(Arrays.asList(item.split(",")));
});
agentNoList.add(agentInfo.getAgentNo());
List<AgentConfig> list = agentConfigService.lambdaQuery()
.in(AgentConfig::getAgentNo, agentNoList)
.eq(AgentConfig::getGroupKey, "agentSiteConfig")
.eq(AgentConfig::getConfigKey, "agentSiteUrl")
.list();
if (!list.isEmpty()) {
tokenRes.put("oemSiteUrl", list.get(0).getConfigVal());
}
return tokenRes;
}
// 通过 sysUserId 登录 (一般在app延期使用)
public String authBySysUserId(Long sysUserId, String loginType, String existsCacheKey) {
SysUserEntity sysUser = sysUserService.getById(sysUserId);
if (sysUser == null || sysUser.getState() != CS.YES) {
throw new BizException("用户不存在或状态不可用");
}
return userDetailsProcess(userDetailsService.loadUserByUsername(sysUser.getLoginUsername()), loginType, existsCacheKey, null);
}
/**
* 根据用户ID 更新缓存中的权限集合, 使得分配实时生效
**/
public void refAuthentication(List<Long> sysUserIdList) {
if (sysUserIdList == null || sysUserIdList.isEmpty()) {
return;
}
Map<Long, SysUserEntity> sysUserMap = new HashMap<>();
// 查询 sysUserId 和 state
sysUserService.lambdaQuery()
.in(SysUserEntity::getSysUserId, sysUserIdList)
.list()
.forEach(item -> sysUserMap.put(item.getSysUserId(), item));
for (Long sysUserId : sysUserIdList) {
Collection<String> cacheKeyList = RedisUtil.keys(CS.getCacheKeyToken(sysUserId, "*"));
if (cacheKeyList == null || cacheKeyList.isEmpty()) {
continue;
}
for (String cacheKey : cacheKeyList) {
//用户不存在 || 已禁用 需要删除Redis
SysUserEntity sysUser = sysUserMap.get(sysUserId);
if (sysUser == null || sysUser.getState() == CS.PUB_DISABLE) {
RedisUtil.del(cacheKey);
continue;
}
JeeUserDetails jwtBaseUser = RedisUtil.getObject(cacheKey, JeeUserDetails.class);
if (jwtBaseUser != null) {
// 重新放置sysUser对象
jwtBaseUser.setSysUser(baseConverter.toModel(sysUser));
//查询放置权限数据
jwtBaseUser.setAuthorities(getUserAuthority(jwtBaseUser.getSysUser()));
//保存token 失效时间不变
RedisUtil.set(cacheKey, jwtBaseUser);
}
}
}
}
/**
* 根据用户ID 删除用户缓存信息
**/
public void delAuthentication(List<Long> sysUserIdList) {
if (sysUserIdList == null || sysUserIdList.isEmpty()) {
return;
}
for (Long sysUserId : sysUserIdList) {
Collection<String> cacheKeyList = RedisUtil.keys(CS.getCacheKeyToken(sysUserId, "*"));
if (cacheKeyList == null || cacheKeyList.isEmpty()) {
continue;
}
for (String cacheKey : cacheKeyList) {
RedisUtil.del(cacheKey);
}
}
}
public List<SimpleGrantedAuthority> getUserAuthority(SysUser sysUser) {
//用户拥有的角色集合 需要以ROLE_ 开头, 用户拥有的权限集合
List<String> roleList = sysRoleService.findListByUser(sysUser.getSysUserId());
List<String> entList = sysRoleEntRelaService.selectEntIdsByUserId(sysUser.getSysUserId(), sysUser.getUserType(), sysUser.getSysType());
List<SimpleGrantedAuthority> grantedAuthorities = new LinkedList<>();
roleList.forEach(role -> grantedAuthorities.add(new SimpleGrantedAuthority(role)));
entList.forEach(ent -> grantedAuthorities.add(new SimpleGrantedAuthority(ent)));
return grantedAuthorities;
}
/**
* 获取到userDetail之后的操作
**/
public String userDetailsProcess(UserDetails userDetails, String loginType, String existsCacheKey, String authType) {
JeeUserDetails jeeUserDetails = (JeeUserDetails) userDetails;
// 登录认证类型
if (StringUtils.isNotEmpty(authType)) {
jeeUserDetails.setAuthType(authType);
}
// 登录方式
jeeUserDetails.setLoginType(loginType);
//验证通过后 再查询用户角色和权限信息集合
SysUser sysUser = jeeUserDetails.getSysUser();
// 普通操作员 && 不包含左侧菜单 进行错误提示 (超管 or 扩展员都是通过菜单定义进行查询全部菜单进行过滤,只有普通操作员通过角色功能进行划分)
if (sysUser.getUserType() == SysUser.UEST_TYPE_NORMAL
&& sysEntitlementMapper.userHasLeftMenu(sysUser.getSysUserId(), CS.SYS_ROLE_TYPE.AGENT) <= 0) {
throw new BizException("当前用户未分配任何菜单权限,请联系管理员进行分配后再登录!");
}
// 查询当前用户的服务商信息
AgentInfo agentInfo = agentInfoService.getById(sysUser.getBelongInfoId());
if (agentInfo != null && (agentInfo.getState() == CS.NO)) {
throw new BizException("当前服务商状态不可用!");
}
// 放置权限集合
jeeUserDetails.setAuthorities(getUserAuthority(sysUser));
//生成token
String cacheKey = StringUtils.isNotEmpty(existsCacheKey) ? existsCacheKey : CS.getCacheKeyToken(sysUser.getSysUserId(), IdUtil.fastUUID());
//生成iToken 并放置到缓存
ITokenService.processTokenCache(jeeUserDetails, cacheKey); //处理token 缓存信息
//将信息放置到Spring-security context中
UsernamePasswordAuthenticationToken authenticationRest = new UsernamePasswordAuthenticationToken(jeeUserDetails, null, jeeUserDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationRest);
//返回JWTToken
return JWTUtils.generateToken(new JWTPayload(jeeUserDetails), systemYmlConfig.getJwtSecret());
}
}

View File

@@ -0,0 +1,14 @@
package com.jeequan.jeepay.agent.service;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.interfaces.ICodeSysTypeManager;
import org.springframework.stereotype.Component;
@Component
public class CodeSysTypeManager implements ICodeSysTypeManager {
@Override
public String getCodeSysName() {
return CS.CODE_SYS_NAME_SET.JEEPAY_AGENT;
}
}

View File

@@ -0,0 +1,341 @@
package com.jeequan.jeepay.agent.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/*
* 二维码生成器
*
* @author terrfly
*
* @date 2021/6/8 17:54
*/
public class CodeImgUtil {
private static final Logger _log = LoggerFactory.getLogger(CodeImgUtil.class);
// 二维码尺寸List
private static List<Integer> sizeList = new ArrayList<Integer>();
static {
sizeList.add(258);
sizeList.add(344);
sizeList.add(430);
sizeList.add(860);
sizeList.add(1280);
}
public static List<Integer> getEwmSizeList() {
return sizeList;
}
// 图片宽度的一般
private static final int IMAGE_WIDTH = 25;
private static final int IMAGE_HEIGHT = 25;
private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH / 2;
private static final int FRAME_WIDTH = 2;
// 二维码写码器
private static MultiFormatWriter mutiWriter = new MultiFormatWriter();
/**
*
* @param content
* 二维码显示的文本
* @param width
* 二维码的宽度
* @param height
* 二维码的高度
* @param srcImagePath
* 中间嵌套的图片
* @param destImagePath
* 二维码生成的地址
*/
public static void encode(String content, int width, int height,
String srcImagePath, String destImagePath, String fileName) {
try {
File dir = new File(destImagePath);
_log.error("==================" + destImagePath);
_log.error("==================" + srcImagePath);
if (!dir.exists()) {
_log.error("==================notExist");
boolean result = dir.mkdirs();
_log.error("==================midirsResult" + result);
}
// ImageIO.write 参数 1、BufferedImage 2、输出的格式 3、输出的文件
ImageIO.write(genBarcode(content, width, height, srcImagePath),
"jpg", new File(destImagePath + fileName));
} catch (Exception e) {
_log.error("生成二维码出错", e);
}
}
/**
* 得到BufferedImage
*
* @param content
* 二维码显示的文本
* @param width
* 二维码的宽度
* @param height
* 二维码的高度
* @param srcImagePath
* 中间嵌套的图片
* @return
* @throws WriterException
* @throws IOException
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static BufferedImage genBarcode(String content, int width,
int height, String srcImagePath) throws WriterException,
IOException {
// 读取源图像
BufferedImage scaleImage = scale(srcImagePath, IMAGE_WIDTH,
IMAGE_HEIGHT, false);
int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT];
for (int i = 0; i < scaleImage.getWidth(); i++) {
for (int j = 0; j < scaleImage.getHeight(); j++) {
srcPixels[i][j] = scaleImage.getRGB(i, j);
}
}
java.util.Hashtable hint = new java.util.Hashtable();
hint.put(EncodeHintType.CHARACTER_SET, "utf-8");
hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hint.put(EncodeHintType.MARGIN, 1);
// 生成二维码
BitMatrix matrix = mutiWriter.encode(content, BarcodeFormat.QR_CODE,
width, height, hint);
// 二维矩阵转为一维像素数组
int halfW = matrix.getWidth() / 2;
int halfH = matrix.getHeight() / 2;
int[] pixels = new int[width * height];
for (int y = 0; y < matrix.getHeight(); y++) {
for (int x = 0; x < matrix.getWidth(); x++) {
// 读取图片
if (x > halfW - IMAGE_HALF_WIDTH
&& x < halfW + IMAGE_HALF_WIDTH
&& y > halfH - IMAGE_HALF_WIDTH
&& y < halfH + IMAGE_HALF_WIDTH) {
pixels[y * width + x] = srcPixels[x - halfW
+ IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH];
}
// 在图片四周形成边框
else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
&& x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH
&& y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
+ IMAGE_HALF_WIDTH + FRAME_WIDTH)
|| (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH
&& x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
&& y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
+ IMAGE_HALF_WIDTH + FRAME_WIDTH)
|| (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
&& x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
&& y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
- IMAGE_HALF_WIDTH + FRAME_WIDTH)
|| (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
&& x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
&& y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
+ IMAGE_HALF_WIDTH + FRAME_WIDTH)) {
pixels[y * width + x] = 0xfffffff;
} else {
// 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色;
pixels[y * width + x] = matrix.get(x, y) ? 0xff000000
: 0xfffffff;
}
}
}
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
image.getRaster().setDataElements(0, 0, width, height, pixels);
return image;
}
/**
* 把传入的原始图像按高度和宽度进行缩放,生成符合要求的图标
*
* @param srcImageFile
* 源文件地址
* @param height
* 目标高度
* @param width
* 目标宽度
* @param hasFiller
* 比例不对时是否需要补白true为补白; false为不补白;
* @throws IOException
*/
private static BufferedImage scale(String srcImageFile, int height,
int width, boolean hasFiller) throws IOException {
double ratio = 0.0; // 缩放比例
URL url = new URL(srcImageFile);
BufferedImage srcImage = ImageIO.read(url);
Image destImage = srcImage.getScaledInstance(width, height,
BufferedImage.SCALE_SMOOTH);
// 计算比例
if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) {
if (srcImage.getHeight() > srcImage.getWidth()) {
ratio = (new Integer(height)).doubleValue()
/ srcImage.getHeight();
} else {
ratio = (new Integer(width)).doubleValue()
/ srcImage.getWidth();
}
AffineTransformOp op = new AffineTransformOp(AffineTransform
.getScaleInstance(ratio, ratio), null);
destImage = op.filter(srcImage, null);
}
if (hasFiller) {// 补白
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D graphic = image.createGraphics();
graphic.setColor(Color.white);
graphic.fillRect(0, 0, width, height);
if (width == destImage.getWidth(null)) {
graphic.drawImage(destImage, 0, (height - destImage
.getHeight(null)) / 2, destImage.getWidth(null),
destImage.getHeight(null), Color.white, null);
} else {
graphic.drawImage(destImage,
(width - destImage.getWidth(null)) / 2, 0, destImage
.getWidth(null), destImage.getHeight(null),
Color.white, null);
}
graphic.dispose();
destImage = image;
}
return (BufferedImage) destImage;
}
/**
* 生成图像
* filePath 存放图片的路径
* fileName 图片的名称
* info 生成图片的链接地址例如weixin://wxpay/s/Anp43md
* width 图片的宽度
* height 图片的高度
* @throws WriterException
* @throws IOException
*/
public static String codeImgEncode(String filePath, String fileName, String info, int width, int height) throws WriterException, IOException {
String format="png";
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix bitMatrix = new MultiFormatWriter().encode(info,
BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵
Path path = FileSystems.getDefault().getPath(filePath, fileName);
File dir = new File(filePath);
_log.error("==================" + filePath);
if (!dir.exists()) {
_log.error("==================notExist");
boolean result = dir.mkdirs();
_log.error("==================midirsResult" + result);
}
MatrixToImageWriter.writeToPath(bitMatrix, format, path);// 输出图像
return path.toString();
}
public static void writeQrCode(OutputStream stream, String info, int width, int height) throws WriterException, IOException {
String format="png";
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.MARGIN,0);
BitMatrix bitMatrix = new MultiFormatWriter().encode(info,
BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵
bitMatrix = deleteWhite(bitMatrix);
BufferedImage bi = MatrixToImageWriter.toBufferedImage(bitMatrix);
bi = zoomInImage(bi,width,height);
ImageIO.write(bi,format,stream); // 输出图像
//MatrixToImageWriter.writeToStream(bitMatrix, format, stream);// 输出图像
}
/**
* 解析图像
*/
public static void codeImgDecode() {
String filePath = "D://zxing.png";
BufferedImage image;
try {
image = ImageIO.read(new File(filePath));
LuminanceSource source = new BufferedImageLuminanceSource(image);
Binarizer binarizer = new HybridBinarizer(source);
BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
Result result = new MultiFormatReader().decode(binaryBitmap, hints);// 对图像进行解码
JSONObject content = JSON.parseObject(result.getText());
System.out.println("图片中内容: ");
System.out.println("author " + content.getString("author"));
System.out.println("zxing " + content.getString("zxing"));
System.out.println("图片中格式: ");
System.out.println("encode " + result.getBarcodeFormat());
} catch (IOException e) {
e.printStackTrace();
} catch (NotFoundException e) {
e.printStackTrace();
}
}
/**
* 去除白边
* */
private static BitMatrix deleteWhite(BitMatrix matrix) {
int[] rec = matrix.getEnclosingRectangle();
int resWidth = rec[2] + 1;
int resHeight = rec[3] + 1;
BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
resMatrix.clear();
for (int i = 0; i < resWidth; i++) {
for (int j = 0; j < resHeight; j++) {
if (matrix.get(i + rec[0], j + rec[1])) {
resMatrix.set(i, j);
}
}
}
return resMatrix;
}
public static BufferedImage zoomInImage(BufferedImage originalImage, int wigth, int height){
BufferedImage newImage = new BufferedImage(wigth,height,originalImage.getType());
Graphics g = newImage.getGraphics();
g.drawImage(originalImage,0,0,wigth,height,null);
g.dispose();
return newImage;
}
}

View File

@@ -0,0 +1,55 @@
package com.jeequan.jeepay.agent.web;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.utils.ApiResBodyAdviceKit;
import com.jeequan.jeepay.core.utils.JsonKit;
import com.jeequan.jeepay.service.impl.SysConfigService;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* 自定义springMVC返回数据格式
*
* @author terrfly
* @modify zhuxiao
* @date 2021-04-27 15:50
*/
@ControllerAdvice
public class ApiResBodyAdvice implements ResponseBodyAdvice {
/** 判断哪些需要拦截 **/
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
/** 拦截返回数据处理 */
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
// 如果为 ApiRes && code为成功态 根据设置做数据传输的加密项 && 系统配置的为传输加密
if( body instanceof ApiRes && ((ApiRes)body).getCode() != null && ((ApiRes)body).getCode().equals(ApiCodeEnum.SUCCESS.getCode())
&& SysConfigService.HTTP_MSG_IS_ENCRYPT
){
// 获取到转换后的格式并且转回ApiRes
ApiRes result = ((JSONObject)ApiResBodyAdviceKit.beforeBodyWrite(body)).toJavaObject(ApiRes.class);
if(result.getData() != null){ //若原始数据不为空
result.setEncryptData(SysConfigService.HTTP_MESSAGE_ENCRYPT_SM4.encryptBase64(JsonKit.newJson("originData", result.getData()).toJSONString()));
result.setData(null);
}
return result;
}
//处理扩展字段
return ApiResBodyAdviceKit.beforeBodyWrite(body);
}
}

View File

@@ -0,0 +1,31 @@
package com.jeequan.jeepay.agent.web;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 数据响应拦截器
*
* @author terrfly
* @modify zhuxiao
* @date 2021-04-27 15:50
*/
@Component
public class ApiResInterceptor implements HandlerInterceptor {
/** postHandler是在请求结束之后, 视图渲染之前执行的,但只有preHandle方法返回true的时候才会执行
* 如果ctrl使用了@RestController或者@ResponseBody注解 则ModelAndView = null, 因为不走视图转换器, 而是走的RequestResponseBodyMethodProcessor。
* ————————————————
*
* **/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//do
}
}

View File

@@ -0,0 +1,66 @@
package com.jeequan.jeepay.agent.web;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
/**
* 上下文配置
*
* @author terrfly
* @modify zhuxiao
* @date 2021-04-27 15:50
*/
@Service
public class ApplicationContextKit implements ServletContextAware,InitializingBean{
private ServletContext servletContext ;
@Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
/**
* afterPropertiesSet 是在什么之后执行? 启动顺序是?
* 调用PropKitSpringBeansUtil.getBean获取方式 会不会出现找不到bean的问题
*
* */
@Override
public void afterPropertiesSet() throws Exception {
}
/**
* 仅在项目启动完成并且在req请求中使用
* @param key
* @return
*/
public static Object getReqSession(String key){
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return request.getSession().getAttribute(key);
}
/**
* 仅在项目启动完成并且在req请求中使用
* @param key
* @return
*/
public static void clearSession(String key){
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
request.getSession().removeAttribute(key);
}
}

View File

@@ -0,0 +1,26 @@
package com.jeequan.jeepay.agent.web;
import com.jeequan.jeepay.core.config.WebConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
/**
* webmvc配置
*
* @author terrfly
* @modify zhuxiao
* @date 2021-04-27 15:50
*/
@Configuration
public class WebmvcConfig extends WebConfig {
@Autowired
private ApiResInterceptor apiResInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(apiResInterceptor);
}
}

View File

@@ -0,0 +1,21 @@
package com.jeequan.jeepay.agent.websocket.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/*
* 开启WebSocket支持
*
* @author terrfly
*
* @date 2021/6/22 12:57
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

View File

@@ -0,0 +1,152 @@
package com.jeequan.jeepay.agent.websocket.server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* WebSocket服务类
* /ws/channelUserId/{appId}/{客戶端自定義ID}
*
* @author terrfly
*
* @date 2021/8/13 18:57
*/
@ServerEndpoint("/api/anon/ws/channelUserId/{appId}/{cid}")
@Component
public class WsChannelUserIdServer {
private final static Logger logger = LoggerFactory.getLogger(WsChannelUserIdServer.class);
//当前在线客户端 数量
private static int onlineClientSize = 0;
// appId 与 WsPayOrderServer 存储关系, ConcurrentHashMap保证线程安全
private static Map<String, Set<WsChannelUserIdServer>> wsAppIdMap = new ConcurrentHashMap<>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//客户端自定义ID
private String cid = "";
//支付订单号
private String appId = "";
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("appId") String appId, @PathParam("cid") String cid) {
try {
//设置当前属性
this.cid = cid;
this.appId = appId;
this.session = session;
Set<WsChannelUserIdServer> wsServerSet = wsAppIdMap.get(appId);
if(wsServerSet == null) {
wsServerSet = new CopyOnWriteArraySet<>();
}
wsServerSet.add(this);
wsAppIdMap.put(appId, wsServerSet);
addOnlineCount(); //在线数加1
logger.info("cid[{}],appId[{}]连接开启监听!当前在线人数为{}", cid, appId, onlineClientSize);
} catch (Exception e) {
logger.error("ws监听异常cid[{}],appId[{}]", cid, appId, e);
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
Set wsSet = wsAppIdMap.get(this.appId);
wsSet.remove(this);
if(wsSet.isEmpty()) {
wsAppIdMap.remove(this.appId);
}
subOnlineCount(); //在线数减1
logger.info("cid[{}],appId[{}]连接关闭!当前在线人数为{}", cid, appId, onlineClientSize);
}
/**
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
logger.error("ws发生错误", error);
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 根据订单ID,推送消息
* 捕捉所有的异常,避免影响业务。
* @param appId
*/
public static void sendMsgByAppAndCid(String appId, String cid, String msg) {
try {
logger.info("推送ws消息到浏览器, appId={}, cid={}, msg={}", appId, cid, msg);
Set<WsChannelUserIdServer> wsSet = wsAppIdMap.get(appId);
if(wsSet == null || wsSet.isEmpty()){
logger.info("appId[{}] 无ws监听客户端", appId);
return ;
}
for (WsChannelUserIdServer item : wsSet) {
if(!cid.equals(item.cid)){
continue;
}
try {
item.sendMessage(msg);
} catch (Exception e) {
logger.info("推送设备消息时异常appId={}, cid={}", appId, item.cid, e);
continue;
}
}
} catch (Exception e) {
logger.info("推送消息时异常appId={}", appId, e);
}
}
public static synchronized int getOnlineClientSize() {
return onlineClientSize;
}
public static synchronized void addOnlineCount() {
onlineClientSize++;
}
public static synchronized void subOnlineCount() {
onlineClientSize--;
}
}

View File

@@ -0,0 +1,149 @@
package com.jeequan.jeepay.agent.websocket.server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
/*
* WebSocket服务类
* /ws/payOrder/{訂單ID}/{客戶端自定義ID}
*
* @author terrfly
*
* @date 2021/6/22 12:57
*/
@ServerEndpoint("/api/anon/ws/payOrder/{payOrderId}/{cid}")
@Component
public class WsPayOrderServer {
private final static Logger logger = LoggerFactory.getLogger(WsPayOrderServer.class);
//当前在线客户端 数量
private static int onlineClientSize = 0;
// payOrderId 与 WsPayOrderServer 存储关系, ConcurrentHashMap保证线程安全
private static Map<String, Set<WsPayOrderServer>> wsOrderIdMap = new ConcurrentHashMap<>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//客户端自定义ID
private String cid = "";
//支付订单号
private String payOrderId = "";
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("payOrderId") String payOrderId, @PathParam("cid") String cid) {
try {
//设置当前属性
this.cid = cid;
this.payOrderId = payOrderId;
this.session = session;
Set<WsPayOrderServer> wsServerSet = wsOrderIdMap.get(payOrderId);
if(wsServerSet == null) {
wsServerSet = new CopyOnWriteArraySet<>();
}
wsServerSet.add(this);
wsOrderIdMap.put(payOrderId, wsServerSet);
addOnlineCount(); //在线数加1
logger.info("cid[{}],payOrderId[{}]连接开启监听!当前在线人数为{}", cid, payOrderId, onlineClientSize);
} catch (Exception e) {
logger.error("ws监听异常cid[{}],payOrderId[{}]", cid, payOrderId, e);
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
Set wsSet = wsOrderIdMap.get(this.payOrderId);
wsSet.remove(this);
if(wsSet.isEmpty()) {
wsOrderIdMap.remove(this.payOrderId);
}
subOnlineCount(); //在线数减1
logger.info("cid[{}],payOrderId[{}]连接关闭!当前在线人数为{}", cid, payOrderId, onlineClientSize);
}
/**
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
logger.error("ws发生错误", error);
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 根据订单ID,推送消息
* 捕捉所有的异常,避免影响业务。
* @param payOrderId
*/
public static void sendMsgByOrderId(String payOrderId, String msg) {
try {
logger.info("推送ws消息到浏览器, payOrderId={}msg={}", payOrderId, msg);
Set<WsPayOrderServer> wsSet = wsOrderIdMap.get(payOrderId);
if(wsSet == null || wsSet.isEmpty()){
logger.info("payOrderId[{}] 无ws监听客户端", payOrderId);
return ;
}
for (WsPayOrderServer item : wsSet) {
try {
item.sendMessage(msg);
} catch (Exception e) {
logger.info("推送设备消息时异常payOrderId={}, cid={}", payOrderId, item.cid, e);
continue;
}
}
} catch (Exception e) {
logger.info("推送消息时异常payOrderId={}", payOrderId, e);
}
}
public static synchronized int getOnlineClientSize() {
return onlineClientSize;
}
public static synchronized void addOnlineCount() {
onlineClientSize++;
}
public static synchronized void subOnlineCount() {
onlineClientSize--;
}
}

View File

@@ -0,0 +1,121 @@
#################################
# spring boot支持外部application.yml 读取优先级为:
# 1、file:./config/当前目录下的config文件夹
# 2、file:./(当前目录)
# 3、classpath:/config/classpath下的config目录
# 4、classpath:/classpath根目录
# 建议: 如果是jar则放置到与jar相同的目录下 如果解压文件放置到classpath: config目录下。 (需要将文件重命名为 application.yml )
#
# 该yml文件只配置与环境相关的参数 其他配置读取项目下的配置项
#
#################################
# 数据库的配置项, 自定义配置放置在配置顶层
#db-config:
# master: #主库配置(必填)
# # yml填写url连接串 无需将&符号进行转义
# url: jdbc:mysql://127.0.0.1:3306/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
# username: root
# password: YinShangFuMysql@123456
# encrypt-account: false # 连接账号和密码是否已加密。 truedb的账密需配置密文函数详见 DBProp.main() false: db账密请填写明文
# # 连接池配置项
# initial-size: 5 #初始化时建立物理连接的个数
# min-idle: 5 #最小连接池数量
# max-active: 30 #最大连接池数量
# max-wait: 60000 #获取连接时最大等待时间,单位毫秒
# # 检测相关
# test-while-idle: true # 建议配置为true不影响性能并且保证安全性。申请连接的时候检测如果空闲时间大于timeBetweenEvictionRunsMillis执行validationQuery检测连接是否有效。
# test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。
# test-on-return: false # 归还连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。
# time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
# min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间
# validation-query: SELECT 1 FROM DUAL
# # 是否缓存preparedStatement
# pool-prepared-statements: false # 是否缓存preparedStatement也就是PSCache。PSCache对支持游标的数据库性能提升巨大比如说oracle。在mysql下建议关闭。
# max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache必须配置大于0当大于0时poolPreparedStatements自动触发修改为true。
# # 配置监控统计拦截的filters去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能慢SQL记录
# filters: stat,wall
# connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
#
# slave: #从库配置(可选), 若没有显式配置则使用master的配置项。 配置参数与master一致。
# spring-boot组件配置
spring:
servlet:
multipart:
enabled: true #是否启用http上传处理
max-request-size: 10MB #最大请求文件的大小
max-file-size: 10MB #设置单个文件最大长度
freemarker:
template-loader-path: classpath:/templates #freemarker模板目录
template-encoding: UTF-8
suffix: .ftl
settings:
classic_compatible: true # 如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较
number_format: '#' #数字格式进行原样显示,不加格式化字符例如 100,00
# #activeMQ配置 ( 注意: activeMQ配置项需在spring的下级 )
# activemq:
# broker-url: failover:(tcp://127.0.0.1:61616?wireFormat.maxInactivityDuration=0) #连接地址
# in-memory: false # Jeepay项目不可使用内存模式 需要连接多个消费者。
# user: system # activeMQ默认无需账密认证。 打开认证activemq.xml添加simpleAuthenticationPlugin标签账密在credentials.properties文件。
# password: manager
# pool:
# enabled: true
# max-connections: 10
# idle-timeout: 30000 # 空闲的连接过期时间默认为30秒
#
#rabbitmq配置 ( 注意: rabbitmq配置项需在spring的下级 )
## rocketmq配置 ( 注意rocketmq配置项请放置到根目录 不是spring的二级配置 )
#rocketmq:
# name-server: 127.0.0.1:9876
# producer:
# group: JEEPAY-GROUP
## 阿里云rocketmq配置 ( 注意aliyun-rocketmq配置项请放置到根目录 不是spring的二级配置需要阿里云开通rocketMQ产品创建Group和Topic )
#aliyun-rocketmq:
# namesrvAddr: xxx
# accessKey: xxx
# secretKey: xxx
# groupIdPrefix: GID_JEEPAY_ # (分组前缀, 具体名称详见AliyunRocketMQFactory.java )
#日志配置参数。
# 当存在logback-spring.xml文件时 该配置将引进到logback配置 springboot配置不生效。
# 不存在logback-spring.xml 文件时, 使用springboot的配置 同样可用。
web:
resources:
static-locations: classpath:/static
logging:
level:
root: debug #主日志级别
com.jeequan.jeepay: debug #该项目日志级别当需要打印sql时请开启为debug
file:
path: ./agent/logs #日志存放地址
#系统业务参数
isys:
jwt-secret: N7qDoevBDZYIfHTq #生成jwt的秘钥。 要求每个系统有单独的秘钥管理机制。
db-encrypt-secret: 1234567890123456 #DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!]
http-message-encrypt-secret: 1234567890123456 #web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!]
# 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更!
sys-RSA2-private-key: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCLU0lXJu9vcJCwrwFGwT1CqXUSY+JMW2iSRPtgLw6lxjU403hS1VyKxA5uTZokv80Wd+bcxDMrM9DwHeGqhjlWvbB/lqaRliJJRdgLVUedrDY+3YSN75uHBtLmxZbnaUpV6/aWA/a+lkNqHxYCWB1jggFB9DhVg2SgoMGDOYHDNA5ZDl47sKpanW0kfG9lINSV4xgDPmAJxUnhkG/7eVEBDev9EIhc+LIMC7Zj+UYc+s/TK4c31fFTW4dZAp3LVEdct9qXU5qm/fXIXxeo3E0bWyOP3VL4Xmx2S9Host1YzjzXPSi1TJjX7rxQkhmbE/dQJ+ws/VvKPuUpmLEPGsm/AgMBAAECggEBAIONCFq58KoQZw3ssA/WtbkTt+69URc31+0EJTYUOIheNjKJubq8qrx7kgSkUT8RutvUKq+YsZfBPS77h/Ay/EDiqpxN6sjcMVNuFyfcRdqimDWTg21hKEC+OLSdLHcj+4RVYGcVJw2dY9n3sBhWiqlCP12+8tILViA0qYL18YgVYJM3bL2MCXfUnm8/Rn1ut5LuDtU/UuaVz9vuCqNirZJedZx3WEq69ZRt9m44XN934NikbUGxQRlz32WRXDo+ssSTu3174UbDYc8nhqO0jUvuzfjOOMf9NYRJsgqVihxMLvvMaUhEE3w6qZPLMj6KhTiG5QHexBbyLgDxH4TZ4gECgYEAz7vZFMoKYifCi+eFykH/ad8QYYoYLlrU1EN2fpIJqwSHZbpBfB8NM5Ov26xU/aNHGKxtSOrUFva5sWub5f9OlsOAmaUOPuVuaJbsq+e3cNQ41jBcdppGJLNx1p/69zR1rF9TbI9Ambd8sOgX3OZmImA2Ldlk2KvMKRruxwc4uN8CgYEAq7J0u5KTwI3PxENLWQ/6tOBNdbCoyqFM+FdANVHRA4dhhdoJ1x0bpdt3tapPFJTBURSEspNxPl4iT+GdpoF6KwqTsQFmB5TLlfx8wY9SIc+sI/ifZvMA5Dv8vVfYWNig7rGV+vIyJCCNbJ5OMa1xvxTDc7Dx4XPxcJ4sR1ZyqyECgYAe447O8ZADsmfSR9X0EkY5ZurXpiIcWnNFMNbg0TRQ0raTYNO18iQTZEWFA6YLpQjAWXtSmWB6HavU/uxKkeEMt/taXVm17oWxVafRk/4J7/SXnM9S73O4p1opENbPhWRuAiq0fMSdVtRatdg+h5/uQqIrxSSit0D/Z7rTq3Y6vwKBgQCd8AlbJckOHiTZd8GOypkm2xHFydxqkJfZ9YCVy44Fvfnig5/7pcXx+oEStfgKiY+OQt6R2fkYksTjUDmRmZbEkvUqpIuzO5dOf7RO5MR7X6oMaL5QmAXg7KFflrfnelYHW4oIDdQ70UnmeXSaU97HE5V7DXBioCGfI5C9inLuoQKBgQCwJmQ2heyTbG1DIBuqf+GFXLuOp76M/7S9c+5R7yfxyTzAbiKRIPeSF5wlxNXEnGwK7qB9CmctlBdnV7A0qnZVFMXf7AbBDUzOCjiy1RSh04BNPnu0dTIygX2PE5inltrHiZtTgciKwj9MexT97F4mTR76kIMz5SGNZe3PscQr7g==
sys-RSA2-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1NJVybvb3CQsK8BRsE9Qql1EmPiTFtokkT7YC8OpcY1ONN4UtVcisQObk2aJL/NFnfm3MQzKzPQ8B3hqoY5Vr2wf5amkZYiSUXYC1VHnaw2Pt2Eje+bhwbS5sWW52lKVev2lgP2vpZDah8WAlgdY4IBQfQ4VYNkoKDBgzmBwzQOWQ5eO7CqWp1tJHxvZSDUleMYAz5gCcVJ4ZBv+3lRAQ3r/RCIXPiyDAu2Y/lGHPrP0yuHN9XxU1uHWQKdy1RHXLfal1Oapv31yF8XqNxNG1sjj91S+F5sdkvR6LLdWM481z0otUyY1+68UJIZmxP3UCfsLP1byj7lKZixDxrJvwIDAQAB
#是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时应开启此配置或在nginx统一配置允许跨域]
allow-cors: true
#是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常 false表示直接查询DB.
cache-config: false
oss:
file-root-path: /home/jeepay/upload #存储根路径 ( 无需以‘/’结尾 )
file-public-path: ${isys.oss.file-root-path}/public #公共读取块 ( 一般配合root-path参数进行设置需以/ 开头, 无需以‘/’结尾 )
file-private-path: ${isys.oss.file-root-path}/private #私有化本地访问不允许url方式公共读取 ( 一般配合root-path参数进行设置需以/ 开头, 无需以‘/’结尾 )
mq:
vender: rabbitMQ # 切换MQ厂商 支持:【 activeMQ rabbitMQ rocketMQ aliYunRocketMQ 】, 需正确配置 【对应的yml参数】 和 【jeepay-components-mq项目下pom.xml中的依赖包】。

View File

@@ -0,0 +1,115 @@
# spring-boot组件配置
spring:
servlet:
multipart:
enabled: true #是否启用http上传处理
max-request-size: 10MB #最大请求文件的大小
max-file-size: 10MB #设置单个文件最大长度
freemarker:
template-loader-path: classpath:/templates #freemarker模板目录
template-encoding: UTF-8
suffix: .ftl
settings:
classic_compatible: true # 如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较
number_format: '#' #数字格式进行原样显示,不加格式化字符例如 100,00
cache:
type: redis
redis:
host: 127.0.0.1
port: 6379
timeout: 1000
password: ax123456ax
activemq:
broker-url: failover:(tcp://127.0.0.1:61616?wireFormat.maxInactivityDuration=0) #
in-memory: false # Jeepay
user: admin # activeMQ
password: 123456
pool:
enabled: true
max-connections: 10
idle-timeout: 30000 #
web:
resources:
static-locations: classpath:/static
logging:
level:
root: info #主日志级别
# xxl-job 执行器配置项
xxl-job:
executor:
admin-address: http://127.0.0.1:8282/xxl-job-admin # 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
access-token: jeepayTaskToken@2022 # 执行器通讯TOKEN
# appname: jeepay-plus-bill-executor # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
# port: # 执行器端口号 [选填]小于等于0则自动获取默认端口为9999单机部署多个执行器时注意要配置不同执行器端口
log-path: ${logging.file.path} # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
logretentiondays: 7 # 执行器日志文件保存天数 [选填] 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
db-config:
master: #主库配置(必填)
# yml填写url连接串 无需将&符号进行转义
url: jdbc:p6spy:mysql://rm-bp1c8prh6j399epb5.mysql.rds.aliyuncs.com/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
username: yinshangfu
password: YinShangFuMysql@123456
encrypt-account: false # 连接账号和密码是否已加密。 truedb的账密需配置密文函数详见 DBProp.main() false: db账密请填写明文
# 连接池配置项
initial-size: 5 #初始化时建立物理连接的个数
min-idle: 5 #最小连接池数量
max-active: 30 #最大连接池数量
max-wait: 60000 #获取连接时最大等待时间,单位毫秒
# 检测相关
test-while-idle: true # 建议配置为true不影响性能并且保证安全性。申请连接的时候检测如果空闲时间大于timeBetweenEvictionRunsMillis执行validationQuery检测连接是否有效。
test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。
test-on-return: false # 归还连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间
validation-query: SELECT 1 FROM DUAL
# 是否缓存preparedStatement
pool-prepared-statements: false # 是否缓存preparedStatement也就是PSCache。PSCache对支持游标的数据库性能提升巨大比如说oracle。在mysql下建议关闭。
max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache必须配置大于0当大于0时poolPreparedStatements自动触发修改为true。
# 配置监控统计拦截的filters去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能慢SQL记录
filters: stat,wall
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
slave: #从库配置(可选), 若没有显式配置则使用master的配置项。 配置参数与master一致。
# yml填写url连接串 无需将&符号进行转义
url: jdbc:p6spy:mysql://rm-bp1c8prh6j399epb5.mysql.rds.aliyuncs.com/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
username: yinshangfu
password: YinShangFuMysql@123456
encrypt-account: false # 连接账号和密码是否已加密。 truedb的账密需配置密文函数详见 DBProp.main() false: db账密请填写明文
# 连接池配置项
initial-size: 5 #初始化时建立物理连接的个数
min-idle: 5 #最小连接池数量
max-active: 30 #最大连接池数量
max-wait: 60000 #获取连接时最大等待时间,单位毫秒
# 检测相关
test-while-idle: true # 建议配置为true不影响性能并且保证安全性。申请连接的时候检测如果空闲时间大于timeBetweenEvictionRunsMillis执行validationQuery检测连接是否有效。
test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。
test-on-return: false # 归还连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间
validation-query: SELECT 1 FROM DUAL
# 是否缓存preparedStatement
pool-prepared-statements: false # 是否缓存preparedStatement也就是PSCache。PSCache对支持游标的数据库性能提升巨大比如说oracle。在mysql下建议关闭。
max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache必须配置大于0当大于0时poolPreparedStatements自动触发修改为true。
# 配置监控统计拦截的filters去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能慢SQL记录
filters: stat,wall
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
isys:
#是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时应开启此配置或在nginx统一配置允许跨域]
allow-cors: true
db-encrypt-secret: 1234567890123456 #DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!]
http-message-encrypt-secret: 1234567890123456 #web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!]
# 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更!
sys-RSA2-private-key: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCLU0lXJu9vcJCwrwFGwT1CqXUSY+JMW2iSRPtgLw6lxjU403hS1VyKxA5uTZokv80Wd+bcxDMrM9DwHeGqhjlWvbB/lqaRliJJRdgLVUedrDY+3YSN75uHBtLmxZbnaUpV6/aWA/a+lkNqHxYCWB1jggFB9DhVg2SgoMGDOYHDNA5ZDl47sKpanW0kfG9lINSV4xgDPmAJxUnhkG/7eVEBDev9EIhc+LIMC7Zj+UYc+s/TK4c31fFTW4dZAp3LVEdct9qXU5qm/fXIXxeo3E0bWyOP3VL4Xmx2S9Host1YzjzXPSi1TJjX7rxQkhmbE/dQJ+ws/VvKPuUpmLEPGsm/AgMBAAECggEBAIONCFq58KoQZw3ssA/WtbkTt+69URc31+0EJTYUOIheNjKJubq8qrx7kgSkUT8RutvUKq+YsZfBPS77h/Ay/EDiqpxN6sjcMVNuFyfcRdqimDWTg21hKEC+OLSdLHcj+4RVYGcVJw2dY9n3sBhWiqlCP12+8tILViA0qYL18YgVYJM3bL2MCXfUnm8/Rn1ut5LuDtU/UuaVz9vuCqNirZJedZx3WEq69ZRt9m44XN934NikbUGxQRlz32WRXDo+ssSTu3174UbDYc8nhqO0jUvuzfjOOMf9NYRJsgqVihxMLvvMaUhEE3w6qZPLMj6KhTiG5QHexBbyLgDxH4TZ4gECgYEAz7vZFMoKYifCi+eFykH/ad8QYYoYLlrU1EN2fpIJqwSHZbpBfB8NM5Ov26xU/aNHGKxtSOrUFva5sWub5f9OlsOAmaUOPuVuaJbsq+e3cNQ41jBcdppGJLNx1p/69zR1rF9TbI9Ambd8sOgX3OZmImA2Ldlk2KvMKRruxwc4uN8CgYEAq7J0u5KTwI3PxENLWQ/6tOBNdbCoyqFM+FdANVHRA4dhhdoJ1x0bpdt3tapPFJTBURSEspNxPl4iT+GdpoF6KwqTsQFmB5TLlfx8wY9SIc+sI/ifZvMA5Dv8vVfYWNig7rGV+vIyJCCNbJ5OMa1xvxTDc7Dx4XPxcJ4sR1ZyqyECgYAe447O8ZADsmfSR9X0EkY5ZurXpiIcWnNFMNbg0TRQ0raTYNO18iQTZEWFA6YLpQjAWXtSmWB6HavU/uxKkeEMt/taXVm17oWxVafRk/4J7/SXnM9S73O4p1opENbPhWRuAiq0fMSdVtRatdg+h5/uQqIrxSSit0D/Z7rTq3Y6vwKBgQCd8AlbJckOHiTZd8GOypkm2xHFydxqkJfZ9YCVy44Fvfnig5/7pcXx+oEStfgKiY+OQt6R2fkYksTjUDmRmZbEkvUqpIuzO5dOf7RO5MR7X6oMaL5QmAXg7KFflrfnelYHW4oIDdQ70UnmeXSaU97HE5V7DXBioCGfI5C9inLuoQKBgQCwJmQ2heyTbG1DIBuqf+GFXLuOp76M/7S9c+5R7yfxyTzAbiKRIPeSF5wlxNXEnGwK7qB9CmctlBdnV7A0qnZVFMXf7AbBDUzOCjiy1RSh04BNPnu0dTIygX2PE5inltrHiZtTgciKwj9MexT97F4mTR76kIMz5SGNZe3PscQr7g==
sys-RSA2-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1NJVybvb3CQsK8BRsE9Qql1EmPiTFtokkT7YC8OpcY1ONN4UtVcisQObk2aJL/NFnfm3MQzKzPQ8B3hqoY5Vr2wf5amkZYiSUXYC1VHnaw2Pt2Eje+bhwbS5sWW52lKVev2lgP2vpZDah8WAlgdY4IBQfQ4VYNkoKDBgzmBwzQOWQ5eO7CqWp1tJHxvZSDUleMYAz5gCcVJ4ZBv+3lRAQ3r/RCIXPiyDAu2Y/lGHPrP0yuHN9XxU1uHWQKdy1RHXLfal1Oapv31yF8XqNxNG1sjj91S+F5sdkvR6LLdWM481z0otUyY1+68UJIZmxP3UCfsLP1byj7lKZixDxrJvwIDAQAB
#是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常 false表示直接查询DB.
cache-config: false
mq:
vender: activeMQ
oss:
file-root-path: /home/www/.upload #存储根路径 ( 无需以‘/’结尾 )
file-public-path: ${isys.oss.file-root-path}/public #公共读取块 ( 一般配合root-path参数进行设置需以/ 开头, 无需以‘/’结尾 )

View File

@@ -0,0 +1,111 @@
# spring-boot组件配置
spring:
servlet:
multipart:
enabled: true #是否启用http上传处理
max-request-size: 10MB #最大请求文件的大小
max-file-size: 10MB #设置单个文件最大长度
resources:
static-locations: classpath:/static #项目静态资源路径 可直接通过http访问
freemarker:
template-loader-path: classpath:/templates #freemarker模板目录
template-encoding: UTF-8
suffix: .ftl
settings:
classic_compatible: true # 如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较
number_format: '#' #数字格式进行原样显示,不加格式化字符例如 100,00
cache:
type: redis
redis:
host: 47.111.143.211
port: 6379
timeout: 1000
password: ax123456ax
rabbitmq:
addresses: 47.111.143.211:5672
username: root
password: YinShangFuRabbit@123456
dynamic: true
virtual-host: /
logging:
level:
root: info #主日志级别
# xxl-job 执行器配置项
xxl-job:
executor:
admin-address: http://47.111.143.211:8282/xxl-job-admin # 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
access-token: jeepayTaskToken@2022 # 执行器通讯TOKEN
# appname: jeepay-plus-bill-executor # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
# port: # 执行器端口号 [选填]小于等于0则自动获取默认端口为9999单机部署多个执行器时注意要配置不同执行器端口
log-path: ${logging.file.path} # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
logretentiondays: 7 # 执行器日志文件保存天数 [选填] 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
db-config:
master: #主库配置(必填)
# yml填写url连接串 无需将&符号进行转义
url: jdbc:mysql://47.111.143.211:3306/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: YinShangFuMysql@123456
encrypt-account: false # 连接账号和密码是否已加密。 truedb的账密需配置密文函数详见 DBProp.main() false: db账密请填写明文
# 连接池配置项
initial-size: 5 #初始化时建立物理连接的个数
min-idle: 5 #最小连接池数量
max-active: 30 #最大连接池数量
max-wait: 60000 #获取连接时最大等待时间,单位毫秒
# 检测相关
test-while-idle: true # 建议配置为true不影响性能并且保证安全性。申请连接的时候检测如果空闲时间大于timeBetweenEvictionRunsMillis执行validationQuery检测连接是否有效。
test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。
test-on-return: false # 归还连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间
validation-query: SELECT 1 FROM DUAL
# 是否缓存preparedStatement
pool-prepared-statements: false # 是否缓存preparedStatement也就是PSCache。PSCache对支持游标的数据库性能提升巨大比如说oracle。在mysql下建议关闭。
max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache必须配置大于0当大于0时poolPreparedStatements自动触发修改为true。
# 配置监控统计拦截的filters去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能慢SQL记录
filters: stat,wall
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
slave: #从库配置(可选), 若没有显式配置则使用master的配置项。 配置参数与master一致。
# yml填写url连接串 无需将&符号进行转义
url: jdbc:mysql://47.111.143.211:3306/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: YinShangFuMysql@123456
encrypt-account: false # 连接账号和密码是否已加密。 truedb的账密需配置密文函数详见 DBProp.main() false: db账密请填写明文
# 连接池配置项
initial-size: 5 #初始化时建立物理连接的个数
min-idle: 5 #最小连接池数量
max-active: 30 #最大连接池数量
max-wait: 60000 #获取连接时最大等待时间,单位毫秒
# 检测相关
test-while-idle: true # 建议配置为true不影响性能并且保证安全性。申请连接的时候检测如果空闲时间大于timeBetweenEvictionRunsMillis执行validationQuery检测连接是否有效。
test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。
test-on-return: false # 归还连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间
validation-query: SELECT 1 FROM DUAL
# 是否缓存preparedStatement
pool-prepared-statements: false # 是否缓存preparedStatement也就是PSCache。PSCache对支持游标的数据库性能提升巨大比如说oracle。在mysql下建议关闭。
max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache必须配置大于0当大于0时poolPreparedStatements自动触发修改为true。
# 配置监控统计拦截的filters去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能慢SQL记录
filters: stat,wall
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
isys:
#是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时应开启此配置或在nginx统一配置允许跨域]
allow-cors: true
db-encrypt-secret: 1234567890123456 #DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!]
http-message-encrypt-secret: 1234567890123456 #web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!]
# 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更!
sys-RSA2-private-key: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCLU0lXJu9vcJCwrwFGwT1CqXUSY+JMW2iSRPtgLw6lxjU403hS1VyKxA5uTZokv80Wd+bcxDMrM9DwHeGqhjlWvbB/lqaRliJJRdgLVUedrDY+3YSN75uHBtLmxZbnaUpV6/aWA/a+lkNqHxYCWB1jggFB9DhVg2SgoMGDOYHDNA5ZDl47sKpanW0kfG9lINSV4xgDPmAJxUnhkG/7eVEBDev9EIhc+LIMC7Zj+UYc+s/TK4c31fFTW4dZAp3LVEdct9qXU5qm/fXIXxeo3E0bWyOP3VL4Xmx2S9Host1YzjzXPSi1TJjX7rxQkhmbE/dQJ+ws/VvKPuUpmLEPGsm/AgMBAAECggEBAIONCFq58KoQZw3ssA/WtbkTt+69URc31+0EJTYUOIheNjKJubq8qrx7kgSkUT8RutvUKq+YsZfBPS77h/Ay/EDiqpxN6sjcMVNuFyfcRdqimDWTg21hKEC+OLSdLHcj+4RVYGcVJw2dY9n3sBhWiqlCP12+8tILViA0qYL18YgVYJM3bL2MCXfUnm8/Rn1ut5LuDtU/UuaVz9vuCqNirZJedZx3WEq69ZRt9m44XN934NikbUGxQRlz32WRXDo+ssSTu3174UbDYc8nhqO0jUvuzfjOOMf9NYRJsgqVihxMLvvMaUhEE3w6qZPLMj6KhTiG5QHexBbyLgDxH4TZ4gECgYEAz7vZFMoKYifCi+eFykH/ad8QYYoYLlrU1EN2fpIJqwSHZbpBfB8NM5Ov26xU/aNHGKxtSOrUFva5sWub5f9OlsOAmaUOPuVuaJbsq+e3cNQ41jBcdppGJLNx1p/69zR1rF9TbI9Ambd8sOgX3OZmImA2Ldlk2KvMKRruxwc4uN8CgYEAq7J0u5KTwI3PxENLWQ/6tOBNdbCoyqFM+FdANVHRA4dhhdoJ1x0bpdt3tapPFJTBURSEspNxPl4iT+GdpoF6KwqTsQFmB5TLlfx8wY9SIc+sI/ifZvMA5Dv8vVfYWNig7rGV+vIyJCCNbJ5OMa1xvxTDc7Dx4XPxcJ4sR1ZyqyECgYAe447O8ZADsmfSR9X0EkY5ZurXpiIcWnNFMNbg0TRQ0raTYNO18iQTZEWFA6YLpQjAWXtSmWB6HavU/uxKkeEMt/taXVm17oWxVafRk/4J7/SXnM9S73O4p1opENbPhWRuAiq0fMSdVtRatdg+h5/uQqIrxSSit0D/Z7rTq3Y6vwKBgQCd8AlbJckOHiTZd8GOypkm2xHFydxqkJfZ9YCVy44Fvfnig5/7pcXx+oEStfgKiY+OQt6R2fkYksTjUDmRmZbEkvUqpIuzO5dOf7RO5MR7X6oMaL5QmAXg7KFflrfnelYHW4oIDdQ70UnmeXSaU97HE5V7DXBioCGfI5C9inLuoQKBgQCwJmQ2heyTbG1DIBuqf+GFXLuOp76M/7S9c+5R7yfxyTzAbiKRIPeSF5wlxNXEnGwK7qB9CmctlBdnV7A0qnZVFMXf7AbBDUzOCjiy1RSh04BNPnu0dTIygX2PE5inltrHiZtTgciKwj9MexT97F4mTR76kIMz5SGNZe3PscQr7g==
sys-RSA2-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1NJVybvb3CQsK8BRsE9Qql1EmPiTFtokkT7YC8OpcY1ONN4UtVcisQObk2aJL/NFnfm3MQzKzPQ8B3hqoY5Vr2wf5amkZYiSUXYC1VHnaw2Pt2Eje+bhwbS5sWW52lKVev2lgP2vpZDah8WAlgdY4IBQfQ4VYNkoKDBgzmBwzQOWQ5eO7CqWp1tJHxvZSDUleMYAz5gCcVJ4ZBv+3lRAQ3r/RCIXPiyDAu2Y/lGHPrP0yuHN9XxU1uHWQKdy1RHXLfal1Oapv31yF8XqNxNG1sjj91S+F5sdkvR6LLdWM481z0otUyY1+68UJIZmxP3UCfsLP1byj7lKZixDxrJvwIDAQAB
#是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常 false表示直接查询DB.
cache-config: false
mq:
vender: rabbitMQ
oss:
file-root-path: D:/jeepayFiles #存储根路径 ( 无需以‘/’结尾 )
file-public-path: ${isys.oss.file-root-path}/public #公共读取块 ( 一般配合root-path参数进行设置需以/ 开头, 无需以‘/’结尾 )

View File

@@ -0,0 +1,8 @@
server:
port: 9219 #设置端口
servlet:
context-path: / #设置应用的目录. 前缀需要带/, 无需设置后缀, 示例 【 /xxx 】 or 【 / 】
spring:
profiles:
active: dev

View File

@@ -0,0 +1,8 @@
__
/ /___ ___ ____ ____ ___ __
__ / // _ \/ _ \/ __ \/ __ `/ / / /
/ /_/ // __/ __/ /_/ / /_/ / /_/ /
\____/ \___/\___/ .___/\__,_/\__, /
/_/ /____/
:: Jeepay Plus S3 :: (v3.3.6.RELEASE)
计全支付 - 让支付接入更简单 : https://www.jeequan.com

View File

@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" debug="false">
<!-- 日志存放路径, 读取application.yml 需要使用springProperty获取 -->
<springProperty scope="context" name="currentLoggerFilePath" source="logging.file.path"/>
<!-- 主日志级别配置 -->
<springProperty scope="context" name="currentRootLevel" source="logging.level.root"/>
<!-- 项目配置, 如修改包名,请搜索并全部替换掉 -->
<springProperty scope="context" name="currentProjectLevel" source="logging.level.com.jeequan.jeepay"/>
<!-- 日志文件名称 logback属性 -->
<property name="currentLoggerFileName" value="agent" />
<!-- 日志格式, 参考https://logback.qos.ch/manual/layouts.html -->
<property name="currentLoggerPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{15} - %msg%n" />
<!-- appender 控制台日志 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8" >
<pattern>${currentLoggerPattern}</pattern>
</encoder>
</appender>
<!-- appender主日志文件 -->
<appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志文件路径及文件名 -->
<file>${currentLoggerFilePath}/${currentLoggerFileName}.all.log</file>
<!-- 内容编码及格式 -->
<encoder charset="UTF-8" ><pattern>${currentLoggerPattern}</pattern></encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${currentLoggerFilePath}/${currentLoggerFileName}.all.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>5</maxHistory> <!--日志文件保留天数-->
</rollingPolicy>
</appender>
<!-- appender错误信息日志文件 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志文件路径及文件名 -->
<file>${currentLoggerFilePath}/${currentLoggerFileName}.error.log</file>
<!-- 内容编码及格式 -->
<encoder charset="UTF-8" ><pattern>${currentLoggerPattern}</pattern></encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${currentLoggerFilePath}/${currentLoggerFileName}.error.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>20</maxHistory> <!--日志文件保留天数-->
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 主日志级别配置 -->
<root level="${currentRootLevel}">
<appender-ref ref="STDOUT" />
<appender-ref ref="ALL_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
<!-- 项目日志级别配置 -->
<logger name="com.jeequan.jeepay" level="${currentProjectLevel}"/>
<logger name="com.jeequan.jeepay.service.mapper" level="info"/>
</configuration>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Some files were not shown because too many files have changed in this diff Show More