This commit is contained in:
韩鹏辉
2024-06-11 10:34:21 +08:00
parent 6bab32173f
commit 7894f47de4
2498 changed files with 442406 additions and 0 deletions

View File

@@ -0,0 +1,172 @@
<?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-components-core</artifactId> <!-- 项目名称 -->
<packaging>jar</packaging> <!-- 项目的最终打包类型/发布形式, 可选[jar, war, pom, maven-plugin]等 -->
<version>${isys.version}</version> <!-- 项目当前版本号 -->
<description>Jeepay计全支付系统 [jeepay-core]</description> <!-- 项目描述 -->
<url>https://www.jeequan.com</url>
<parent>
<groupId>com.jeequan</groupId>
<artifactId>jeepay-components</artifactId>
<version>Final</version>
</parent>
<!-- 项目属性 -->
<properties>
<projectRootDir>${basedir}/../../</projectRootDir>
</properties>
<!-- 项目依赖声明 -->
<dependencies>
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
</dependency>
<!-- 依赖 [spring-context] 基础包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>provided</scope>
</dependency>
<!-- 可选依赖 [spring-redis] -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<scope>provided</scope>
</dependency>
<!-- 添加 spring-webmvc 基础依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<scope>provided</scope> <!-- 仅编译依赖该jar 运行时存在 -->
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope> <!-- 仅编译依赖该jar 运行时存在 -->
</dependency>
<!-- mybatis plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<scope>provided</scope>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<scope>provided</scope>
</dependency>
<!-- alibaba FastJSON -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!-- commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!--阿里云短信依赖-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<scope>provided</scope> <!-- 编译依赖 -->
</dependency>
<!-- 阿里大于 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<scope>provided</scope> <!-- 编译依赖 -->
</dependency>
<!-- hibernate.validator插件 -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<scope>provided</scope> <!-- 编译依赖 -->
</dependency>
<!--easypoi-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes><include>**/*.xml</include></includes><!-- maven可以将mapper.xml进行打包处理否则仅对java文件处理 -->
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<!--class files as source must be available for extension method classes-->
<Contains-Sources>java,class</Contains-Sources>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,20 @@
package com.jeequan.jeepay.core.annotate;
import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum;
import java.lang.annotation.*;
/**
* @description:
* @author: zx
* @date: 2023/04/07 12:09
*/
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface ChannelMchId {
ChannelMchIdTypeEnum type();
}

View File

@@ -0,0 +1,20 @@
package com.jeequan.jeepay.core.annotate;
import com.jeequan.jeepay.core.constants.DesensitizedTypeEnum;
import java.lang.annotation.*;
/**
* @description:
* @author: zx
* @date: 2023/04/07 12:09
*/
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Desensitized {
DesensitizedTypeEnum type();
}

View File

@@ -0,0 +1,42 @@
package com.jeequan.jeepay.core.annotate.kits;
import cn.hutool.core.bean.BeanUtil;
import com.jeequan.jeepay.core.annotate.ChannelMchId;
import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
/**
* @description: 工具类
* @author: zx
* @date: 2023/04/07 12:25
*/
@Slf4j
public class ChannelMchIdKit {
public static String getChannelMchNo(Object javaBean, ChannelMchIdTypeEnum channelMchIdTypeEnum) {
if (null == javaBean) {
return null;
}
final String[] channelMchIdArr = { null };
Class<?> beanClass = javaBean.getClass();
BeanUtil.descForEach(beanClass, i -> {
Field field = i.getField();
Object value = i.getValue(javaBean);
if (null == value) {
return;
}
ChannelMchId annotation = field.getAnnotation(ChannelMchId.class);
if (null != annotation && annotation.type() == channelMchIdTypeEnum) {
channelMchIdArr[0] = (String) value;
}
});
return channelMchIdArr[0];
}
}

View File

@@ -0,0 +1,170 @@
package com.jeequan.jeepay.core.annotate.kits;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.ReflectUtil;
import com.jeequan.jeepay.core.annotate.Desensitized;
import com.jeequan.jeepay.core.model.applyment.IdcardInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* @description: 数据脱敏工具类
* @author: zx
* @date: 2023/04/07 12:25
*/
@Slf4j
public class DesenKit {
/**
* 对象脱敏
* */
public static void desenObject(Object javaBean) {
if (null != javaBean) {
Class<?> beanClass = javaBean.getClass();
BeanUtil.descForEach(beanClass, i -> {
try {
setNewValueForField(javaBean, i.getField(), i.getValue(javaBean));
} catch (IllegalAccessException e) {
log.error("脱敏异常:", e);
}
});
}
}
private static void replace(Field[] fields, Object javaBean, Set<Integer> referenceCounter) throws IllegalArgumentException, IllegalAccessException {
if (null != fields && fields.length > 0) {
for (Field field : fields) {
field.setAccessible(true);
if (null != field && null != javaBean) {
Object value = field.get(javaBean);
if (null != value) {
Class<?> type = value.getClass();
//处理子属性,包括集合中的
if (type.isArray()) {//对数组类型的字段进行递归过滤
int len = Array.getLength(value);
for (int i = 0; i < len; i++) {
Object arrayObject = Array.get(value, i);
if (isNotGeneralType(arrayObject.getClass(), arrayObject, referenceCounter)) {
replace(ReflectUtil.getFields(javaBean.getClass()), arrayObject, referenceCounter);
}
}
} else if (value instanceof Collection<?>) {//对集合类型的字段进行递归过滤
Collection<?> c = (Collection<?>) value;
Iterator<?> it = c.iterator();
while (it.hasNext()) {// TODO: 待优化
Object collectionObj = it.next();
if (isNotGeneralType(collectionObj.getClass(), collectionObj, referenceCounter)) {
replace(ReflectUtil.getFields(javaBean.getClass()), collectionObj, referenceCounter);
}
}
} else if (value instanceof Map<?, ?>) {//对Map类型的字段进行递归过滤
Map<?, ?> m = (Map<?, ?>) value;
Set<?> set = m.entrySet();
for (Object o : set) {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
Object mapVal = entry.getValue();
if (isNotGeneralType(mapVal.getClass(), mapVal, referenceCounter)) {
replace(ReflectUtil.getFields(javaBean.getClass()), mapVal, referenceCounter);
}
}
} else if (value instanceof Enum<?>) {
continue;
}
/*除基础类型、jdk类型的字段之外对其他类型的字段进行递归过滤*/
else {
if (!type.isPrimitive()
&& type.getPackage() != null
&& !StringUtils.startsWith(type.getPackage().getName(), "javax.")
&& !StringUtils.startsWith(type.getPackage().getName(), "java.")
&& !StringUtils.startsWith(field.getType().getName(), "javax.")
&& !StringUtils.startsWith(field.getName(), "java.")
&& referenceCounter.add(value.hashCode())) {
replace(ReflectUtil.getFields(javaBean.getClass()), value, referenceCounter);
}
}
}
//脱敏操作
setNewValueForField(javaBean, field, value);
}
}
}
}
private static boolean isNotGeneralType(Class<?> aClass, Object arrayObject, Set<Integer> referenceCounter) {
return true;
}
public static void setNewValueForField(Object javaBean, Field field, Object value) throws IllegalAccessException {
if (value instanceof Collection<?>) {
Collection<?> c = (Collection<?>) value;
Iterator<?> it = c.iterator();
while (it.hasNext()) {
Object collectionObj = it.next();
if (collectionObj instanceof IdcardInfo) {
desenObject(collectionObj);
}
}
}
//处理自身的属性
Desensitized annotation = field.getAnnotation(Desensitized.class);
if (null == annotation) {
return;
}
if ((field.getType().equals(String.class) || field.getType().equals(Long.class))) {
String valueStr = (String) value;
if (StringUtils.isNotBlank(valueStr)) {
switch (annotation.type()) {
case CHINESE_NAME: {
field.set(javaBean, DesensitizedUtil.chineseName(valueStr));
break;
}
case ID_CARD: {
field.set(javaBean, DesensitizedUtil.idCardNum(valueStr, 3, 4));
break;
}
case FIXED_PHONE: {
field.set(javaBean, DesensitizedUtil.fixedPhone(valueStr));
break;
}
case MOBILE_PHONE: {
field.set(javaBean, DesensitizedUtil.mobilePhone(valueStr));
break;
}
case ADDRESS: {
field.set(javaBean, DesensitizedUtil.address(valueStr, 8));
break;
}
case EMAIL: {
field.set(javaBean, DesensitizedUtil.email(valueStr));
break;
}
case BANK_CARD: {
field.set(javaBean, DesensitizedUtil.bankCard(valueStr));
break;
}
case PASSWORD: {
field.set(javaBean, DesensitizedUtil.password(valueStr));
break;
}
}
}
}
}
}

View File

@@ -0,0 +1,16 @@
package com.jeequan.jeepay.core.aop;
import java.lang.annotation.*;
/*
* 方法级日志切面注解
*
* @author terrfly
* @date 2021/6/8 18:00
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodLog {
String remark() default "";
}

View File

@@ -0,0 +1,205 @@
package com.jeequan.jeepay.core.beans;
import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.service.ISysConfigService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.util.Map;
/**
* 基于spring的 req 工具类
*
* @author terrfly
* @date 2021/6/7 12:16
*/
@Slf4j
@Component
public class RequestKitBean {
@Setter(onMethod_ = @Autowired(required = false))
protected HttpServletRequest request; //自动注入request
@Setter(onMethod_ = @Autowired(required = false))
private ISysConfigService sysConfigService;
/**
* reqContext对象中的key: 转换好的json对象
*/
private static final String REQ_CONTEXT_KEY_PARAMJSON = "REQ_CONTEXT_KEY_PARAMJSON";
/**
* JSON 格式通过请求主体BODY传输 获取参数
**/
public String getReqParamFromBody() {
StringBuilder body = new StringBuilder();
if (isConvertJSON()) {
try {
String str;
while ((str = request.getReader().readLine()) != null) {
body.append(str);
}
return body.toString();
} catch (Exception e) {
log.error("请求参数转换异常! params=[{}]", body);
throw new BizException(ApiCodeEnum.PARAMS_ERROR, "转换异常");
}
} else {
return body.toString();
}
}
/**
* request.getParameter 获取参数 并转换为JSON格式
**/
public JSONObject reqParam2JSON() {
if (isConvertJSON()) {
return getApplicationJson();
}
// Process parameters from request.getParameterMap()
return getFormData();
}
private JSONObject getApplicationJson() {
JSONObject returnObject = new JSONObject();
String str = "";
try (BufferedReader reader = request.getReader()) {
StringBuilder body = new StringBuilder();
while ((str = reader.readLine()) != null && !str.equals("null")) {
body.append(str);
}
if (StringUtils.isEmpty(body.toString())) {
return returnObject;
}
JSONObject result = JSON.parseObject(body.toString());
// Check for encrypted data and decrypt if necessary
if (result.size() == 1 && result.containsKey("encryptData")) {
String encryptedData = result.getString("encryptData");
return JSON.parseObject(sysConfigService.getHttpMessageSM4().decryptStr(encryptedData));
}
return result;
} catch (Exception e) {
log.error("请求参数转换异常! params=[{}], error: {}", str, e.getMessage());
throw new BizException(ApiCodeEnum.PARAMS_ERROR, "Conversion exception");
}
}
private JSONObject getFormData() {
JSONObject returnObject = new JSONObject();
Map<String, String[]> properties = request.getParameterMap();
for (Map.Entry<String, String[]> entry : properties.entrySet()) {
String name = entry.getKey();
String[] values = entry.getValue();
if (ArrayUtil.isNotEmpty(values)) {
// Handle array values efficiently
String value = String.join(",", values);
if (!name.contains("[")) {
returnObject.put(name, value);
} else {
String mainKey = name.substring(0, name.indexOf("["));
String subKey = name.substring(name.indexOf("[") + 1, name.indexOf("]"));
JSONObject subJson = returnObject.containsKey(mainKey)
? returnObject.getJSONObject(mainKey)
: new JSONObject();
subJson.put(subKey, value);
returnObject.put(mainKey, subJson);
}
}
}
return returnObject;
}
/**
* 获取json格式的请求参数
**/
public JSONObject getReqParamJSON() {
//将转换好的reqParam JSON格式的对象保存在当前请求上下文对象中进行保存
// 注意1 springMVC的CTRL默认单例模式 不可使用局部变量保存,会出现线程安全问题;
// 注意2 springMVC的请求模式为线程池如果采用ThreadLocal保存对象信息可能会出现不清空或者被覆盖的问题。
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
Assert.notNull(requestAttributes, "非web环境下该参数可能为空");
Object reqParamObject = requestAttributes.getAttribute(REQ_CONTEXT_KEY_PARAMJSON, RequestAttributes.SCOPE_REQUEST);
if (reqParamObject == null) {
JSONObject reqParam = reqParam2JSON();
requestAttributes.setAttribute(REQ_CONTEXT_KEY_PARAMJSON, reqParam, RequestAttributes.SCOPE_REQUEST);
return reqParam;
}
return (JSONObject) reqParamObject;
}
/**
* 判断请求参数是否转换为json格式
*/
private boolean isConvertJSON() {
String contentType = request.getContentType();
//有contentType && json格式 get请求不转换
//application/json 需要转换为json格式
return contentType != null
&& contentType.toLowerCase().contains("application/json")
&& !request.getMethod().equalsIgnoreCase("GET");
}
/**
* 获取客户端ip地址
**/
public String getClientIp() {
String ipAddress;
ipAddress = request.getHeader("x-forwarded-for");
String unknown = "unknown";
if (ipAddress == null || ipAddress.isEmpty() || unknown.equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.isEmpty() || unknown.equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.isEmpty() || unknown.equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
}
// 对于通过多个代理的情况第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > 15 && (ipAddress.contains(","))) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
return ipAddress;
}
/**
* 贴牌获取域名
**/
public String getdomainName() {
String domainName;
domainName = request.getHeader("Referer");
return domainName;
}
}

View File

@@ -0,0 +1,94 @@
package com.jeequan.jeepay.core.cache;
import com.alibaba.fastjson.JSONArray;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.model.security.JeeUserDetails;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
/**
* token service
*
* @author terrfly
* @date 2021/5/24 09:06
*/
public class ITokenService {
/**
* 处理token信息
* 1. 如果不允许多用户则踢掉之前的所有用户信息
* 2. 更新token 缓存时间信息
* 3. 更新用户token列表
**/
public static void processTokenCache(JeeUserDetails userDetail, String cacheKey) {
userDetail.setCacheKey(cacheKey); //设置cacheKey
//当前用户的所有登录token 集合
// if(!PropKit.isAllowMultiUser()){ //不允许多用户登录
//
// List<String> allTokenList = new ArrayList<>();
// for (String token : allTokenList) {
// if(!cacheKey.equalsIgnoreCase(token)){
// RedisUtil.del(token);
// }
// }
// }
//当前用户的所有登录token 集合
List<String> iTokenList = (List) RedisUtil.getObject(CS.getCacheKeyTokenList(userDetail.getSysUser().getSysUserId()), List.class);
if (iTokenList == null) {
iTokenList = new ArrayList<>();
}
if (!iTokenList.contains(cacheKey)) {
iTokenList.add(cacheKey);
}
//保存token 和 tokenList信息
RedisUtil.set(cacheKey, userDetail, getTokenCacheTime(userDetail.getLoginType())); //缓存时间2小时, 保存具体信息而只是uid, 因为很多场景需要得到信息, 例如验证接口权限, 每次请求都需要获取。 将信息封装在一起减少磁盘请求次数, 如果放置多个key会增加非顺序读取。
RedisUtil.set(CS.getCacheKeyTokenList(userDetail.getSysUser().getSysUserId()), iTokenList, getTokenCacheTime(userDetail.getLoginType())); //缓存时间2小时超时自动清除
}
/**
* 退出时清除token信息
*/
public static void removeIToken(String iToken, Long currentUID) {
//1. 清除token的信息
RedisUtil.del(iToken);
}
/**
* 刷新数据
**/
public static void refData(JeeUserDetails currentUserInfo) {
RedisUtil.set(currentUserInfo.getCacheKey(), currentUserInfo, getTokenCacheTime(currentUserInfo.getLoginType())); //缓存时间2小时, 保存具体信息而只是uid, 因为很多场景需要得到信息, 例如验证接口权限, 每次请求都需要获取。 将信息封装在一起减少磁盘请求次数, 如果放置多个key会增加非顺序读取。
// 获取所有的key
String tokenList = RedisUtil.getString(CS.getCacheKeyTokenList(currentUserInfo.getSysUser().getSysUserId()));
if (StringUtils.isNotEmpty(tokenList)) {
JSONArray.parseArray(tokenList, String.class).forEach(token -> {
if (RedisUtil.hasKey(token)) {
RedisUtil.set(token, currentUserInfo, getTokenCacheTime(currentUserInfo.getLoginType())); //缓存时间2小时, 保存具体信息而只是uid, 因为很多场景需要得到信息, 例如验证接口权限, 每次请求都需要获取。 将信息封装在一起减少磁盘请求次数, 如果放置多个key会增加非顺序读取。
}
});
}
}
/**
* 获取token的缓存时间
**/
public static long getTokenCacheTime(String loginType) {
// 默认两个小时
return CS.TOKEN_TIME;
}
}

View File

@@ -0,0 +1,189 @@
package com.jeequan.jeepay.core.cache;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Redis工具类
*
* @author terrfly
* @date 2021/5/24 17:58
*/
public class RedisUtil {
private static StringRedisTemplate stringRedisTemplate = null;
/** 作用:不同系统的前缀。 a.当连接不同的database时可以为空(物理隔离) b.当redis集群时因为必须同一个database所以需通过前缀区分不同系统的业务。 **/
public static String SYS_PREFIX_KEY = "";
/** 获取redis 中存入的真实KEY **/
public static String getRealKey(String bizKey){
return (SYS_PREFIX_KEY == null ? "" : SYS_PREFIX_KEY) + bizKey;
}
/** 获取redis 中存入的真实KEY : 转换为业务KEY **/
public static String getBizKey(String realKey){
// 前缀说明相同, 无需转换, 参数为空也无需转换
if(StringUtils.isAnyEmpty(realKey, SYS_PREFIX_KEY)){
return realKey;
}
// 不是相同的前缀
if(!realKey.startsWith(SYS_PREFIX_KEY)){
return realKey;
}
// 去掉前缀 就是真实的 业务key
return realKey.substring(SYS_PREFIX_KEY.length());
}
/** 获取RedisTemplate对象, 默认使用 StringRedisTemplate, 客户端可查询 **/
public static StringRedisTemplate getStringRedisTemplate(){
if(stringRedisTemplate == null){
if(SpringBeansUtil.getApplicationContext().containsBean("defaultStringRedisTemplate")){
stringRedisTemplate = SpringBeansUtil.getBean("defaultStringRedisTemplate", StringRedisTemplate.class);
}else{
stringRedisTemplate = SpringBeansUtil.getBean(StringRedisTemplate.class);
}
}
return stringRedisTemplate;
}
/** 获取缓存数据, String类型 */
public static String getString(String key) {
if(key == null) {
return null;
}
return (String)getStringRedisTemplate().opsForValue().get(RedisUtil.getRealKey(key));
}
/** 获取缓存数据对象 */
public static <T> T getObject(String key, Class<T> cls) {
String val = getString(key);
return JSON.parseObject(val, cls);
}
/** 放置缓存对象 */
public static void setString(String key, String value) {
getStringRedisTemplate().opsForValue().set(RedisUtil.getRealKey(key), value);
}
/** 普通缓存放入并设置时间, 默认单位:秒 */
public static void setString(String key, String value, long time) {
getStringRedisTemplate().opsForValue().set(RedisUtil.getRealKey(key), value, time, TimeUnit.SECONDS);
}
/** 普通缓存放入并设置时间 */
public static void setString(String key, String value, long time, TimeUnit timeUnit) {
getStringRedisTemplate().opsForValue().set(RedisUtil.getRealKey(key), value, time, timeUnit);
}
/** 放置缓存对象 */
public static void set(String key, Object value) {
setString(key, JSON.toJSONString(value));
}
/** 普通缓存放入并设置时间, 默认单位:秒 */
public static void set(String key, Object value, long time) {
setString(key, JSON.toJSONString(value), time);
}
/** 普通缓存放入并设置时间 */
public static void set(String key, Object value, long time, TimeUnit timeUnit) {
setString(key, JSON.toJSONString(value), time, timeUnit);
}
/** 指定缓存失效时间 */
public static void expire(String key, long time) {
getStringRedisTemplate().expire(RedisUtil.getRealKey(key), time, TimeUnit.SECONDS);
}
/** 指定缓存失效时间 */
public static void expire(String key, long time, TimeUnit timeUnit) {
getStringRedisTemplate().expire(RedisUtil.getRealKey(key), time, timeUnit);
}
/**
* 根据key 获取过期时间
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public static long getExpire(String key) {
return getStringRedisTemplate().getExpire(RedisUtil.getRealKey(key), TimeUnit.SECONDS);
}
/** 判断key是否存在 */
public static boolean hasKey(String key) {
return getStringRedisTemplate().hasKey(RedisUtil.getRealKey(key));
}
/** 删除缓存根据key **/
public static void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
getStringRedisTemplate().delete(RedisUtil.getRealKey(key[0]));
} else {
List<String> realKeys = new ArrayList<>();
for (String s : key) {
realKeys.add(RedisUtil.getRealKey(s));
}
getStringRedisTemplate().delete(realKeys);
}
}
}
/** 删除缓存根据key前缀 **/
public static void delByPrefix(String keyPrefix) {
StringRedisTemplate redisTemplate = getStringRedisTemplate();
Set<String> keys = redisTemplate.keys(getRealKey(keyPrefix) + "*");
if (CollUtil.isEmpty(keys)) {
return;
}
for (String key : keys) {
redisTemplate.delete(key);
}
}
/** 查询keys */
public static Collection<String> keys(String pattern) {
Collection<String> queryResult = getStringRedisTemplate().keys(RedisUtil.getRealKey(pattern));
if(queryResult == null || queryResult.isEmpty()){
return queryResult;
}
// 转换为: 业务的key
Collection<String> result = new ArrayList<>();
for (String s : queryResult) {
result.add(RedisUtil.getBizKey(s));
}
return result;
}
/** 获取缓存数据, String类型 */
public static Long increment(String key, long delta) {
if(key == null) {
return null;
}
return getStringRedisTemplate().opsForValue().increment(RedisUtil.getRealKey(key), delta);
}
}

View File

@@ -0,0 +1,19 @@
package com.jeequan.jeepay.core.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<URIFilter> customFilter() {
FilterRegistrationBean<URIFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new URIFilter());
registrationBean.addUrlPatterns("/*"); // 设置要过滤的 URL 模式
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); // 设置为最高优先级
return registrationBean;
}
}

View File

@@ -0,0 +1,29 @@
package com.jeequan.jeepay.core.config;
import com.p6spy.engine.spy.appender.MessageFormattingStrategy;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SpySqlFormatConfigure implements MessageFormattingStrategy {
/**
* <p>输出执行sql信息</p >
* @author
* @date 2021/12/3
* @param connectionId
* @param now 执行时间
* @param elapsed 耗时多少毫秒
* @param category
* @param prepared 准备执行的sql脚本
* @param sql 执行的sql脚本
* @param url 数据源连接地址
*/
@Override
public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) {
if (log.isInfoEnabled()) {
log.info("完整sql {}", sql.replaceAll("[\\s]+", " "));
log.info("耗时:{} 毫秒", elapsed);
}
return "";
}
}

View File

@@ -0,0 +1,47 @@
package com.jeequan.jeepay.core.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
//@Component
@Slf4j
public class URIFilter implements Filter {
private final AntPathMatcher pathMatcher = new AntPathMatcher();
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String uri = httpRequest.getRequestURI();
// 判断请求的URI是否为静态资源若是则不打印
if (isStaticResource(uri)) {
// 继续处理请求
chain.doFilter(request, response);
} else {
log.info("Request URI: " + uri);
log.info("Request method: " + httpRequest.getMethod());
log.info("Request remote host: " + httpRequest.getRemoteHost());
// 继续处理请求
chain.doFilter(request, response);
}
}
private boolean isStaticResource(String uri) {
// 静态资源所在的默认路径
String[] staticResourceLocations = {"/static/**", "/public/**", "/resources/**", "/META-INF/resources/**"};
for (String location : staticResourceLocations) {
if (pathMatcher.match(location, uri)) {
return true;
}
}
return false;
}
// 可以在这里实现其他Filter方法但对于打印URI来说doFilter()方法已足够
}

View File

@@ -0,0 +1,30 @@
package com.jeequan.jeepay.core.config;
import com.jeequan.jeepay.core.interceptor.ReqInfoInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class WebConfig implements WebMvcConfigurer {
@Autowired
private ReqInfoInterceptor requestInfoInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestInfoInterceptor);
}
@Bean
public ExecutorService executorService() {
return new ThreadPoolExecutor(4,
4, 1L
, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100), Thread::new, new ThreadPoolExecutor.CallerRunsPolicy());
}
}

View File

@@ -0,0 +1,47 @@
package com.jeequan.jeepay.core.constants;
/*
* 接口返回码
*
* @author terrfly
*
* @date 2021/5/24 17:07
*/
public enum ApiCodeEnum{
SUCCESS(0, "SUCCESS"), //请求成功
CUSTOM_FAIL(9999, "自定义业务异常"), //自定义业务异常
SYSTEM_ERROR(10, "系统异常[%s]"),
PARAMS_ERROR(11, "参数有误[%s]"),
DB_ERROR(12, "数据库服务异常"),
SYS_OPERATION_FAIL_CREATE(5000, "新增失败"),
SYS_OPERATION_FAIL_DELETE(5001, "删除失败"),
SYS_OPERATION_FAIL_UPDATE(5002, "修改失败"),
SYS_OPERATION_FAIL_SEARCH(5003, "记录不存在"),
SYS_PERMISSION_ERROR(5004, "权限错误,当前用户不支持此操作"),
SYS_USER_PWD_EXPIRED(5005, "用户密码已过期,请更改"),
SYS_USER_UN_AUDIT(5006, "用户未通过审核,请提交审核资料"),
YS_ARTIFICIAL_AUDIT_CODE(8001, "银盛进件人工审核");
private int code;
private String msg;
ApiCodeEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode(){
return this.code;
}
public String getMsg() {
return this.msg;
}
}

View File

@@ -0,0 +1,732 @@
package com.jeequan.jeepay.core.constants;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author terrfly
* @Date 2019/11/16 15:09
* @Description Constants 常量对象
**/
public class CS {
/** 可能需要根据环境 进行修改的地方 **/
/**
* DB密码因子 : 规则[必须32位 支持数字和大小写字母]
*/
public final static String DB_PASSWD_DECRYPT_KEY = "jeepayDJeIVzvyD6apRY7CSgmA3LN1Kk";
//登录图形验证码缓存时间单位s
public static final int VERCODE_CACHE_TIME = 60;
/**
* 系统 角色 定义
**/
public interface SYS_ROLE_TYPE {
String PLATFORM = "PLATFORM"; // 平台: 一般指运营平台系统。 或者 或者平台收益者。
String ISV = "ISV"; //服务商角色
String AGENT = "AGENT"; // 服务商系统 or 服务商角色
String MCH = "MCH"; // 商户系统 or 商户角色
/**
* @since 2024-01-28 14:15:14
* 商户/用户费率,不在于应用绑定,后期如果需要用到应用费率,再对现有名词做区分
*/
String MCH_APP = "MCH_APP"; // 商户应用
/**
* 用户进件商户信息
*/
String MCH_APPLYMENT = "MCH_APPLYMENT";
String ISV_OAUTH2 = "ISV_OAUTH2"; // 服务商的oauth2参数
String MCH_APP_OAUTH2 = "MCH_APP_OAUTH2"; // 商户应用的oauth2参数目前仅普通商户
Map<String, String> SYS_ROLE_TYPE_MAP = new HashMap<>();
}
static {
SYS_ROLE_TYPE.SYS_ROLE_TYPE_MAP.put(SYS_ROLE_TYPE.PLATFORM, "运营平台");
SYS_ROLE_TYPE.SYS_ROLE_TYPE_MAP.put(SYS_ROLE_TYPE.AGENT, "服务商系统");
SYS_ROLE_TYPE.SYS_ROLE_TYPE_MAP.put(SYS_ROLE_TYPE.MCH, "商户系统");
SYS_ROLE_TYPE.SYS_ROLE_TYPE_MAP.put(SYS_ROLE_TYPE.ISV, "服务商");
SYS_ROLE_TYPE.SYS_ROLE_TYPE_MAP.put(SYS_ROLE_TYPE.MCH_APP, "商户应用");
SYS_ROLE_TYPE.SYS_ROLE_TYPE_MAP.put(SYS_ROLE_TYPE.MCH_APPLYMENT, "商户应用");
}
/**
* 特殊的infoId 的枚举值
**/
public interface INFO_ID_ENUM {
String PLATFORM_PROFIT = "PLATFORM_PROFIT"; // 运营平台的利润
String PLATFORM_INACCOUNT = "PLATFORM_INACCOUNT"; // 运营平台的三方支付网关的入账金额 (并非利润, 包含了服务商的所有的利润 )
}
/**
* yes or no
**/
public static final byte NO = 0;
public static final byte YES = 1;
/**
* 通用 可用 / 禁用
**/
public static final int PUB_USABLE = 1;
public static final int PUB_DISABLE = 0;
public static final Map<Integer, String> PUB_USABLE_MAP = new HashMap<>();
static {
PUB_USABLE_MAP.put(PUB_USABLE, "正常");
PUB_USABLE_MAP.put(PUB_DISABLE, "停用");
}
/**
* 商户类型:1-普通商户 2-特约商户
*/
public static final byte MCH_TYPE_NORMAL = 1;
public static final byte MCH_TYPE_ISVSUB = 2;
/**
* 性别 1- 男, 2-女
*/
public static final byte SEX_UNKNOWN = 0;
public static final byte SEX_MALE = 1;
public static final byte SEX_FEMALE = 2;
public static final long TOKEN_TIME = 60 * 60 * 2; //单位s, 两小时
public static final long TOKEN_TIME_APP = 60 * 60 * 24 * 30; //单位s, 30天
//access_token 名称
public static final String ACCESS_TOKEN_NAME = "iToken";
public static final String FACE_DEVICE_NAME = "facedevice";
/** 不同系统请放置不同的redis库 **/
/**
* 缓存key: 当前用户所有用户的token集合 example: TOKEN_1001_HcNheNDqHzhTIrT0lUXikm7xU5XY4Q
*/
public static final String CACHE_KEY_TOKEN = "TOKEN_%s_%s";
public static String getCacheKeyToken(Object sysUserId, String uuid) {
return String.format(CACHE_KEY_TOKEN, sysUserId, uuid);
}
/**
* 缓存key: 当前用户所有用户的token集合 example: tokenList_1001
*/
public static final String CACHE_KEY_TOKEN_LIST = "tokenList_%s";
public static String getCacheKeyTokenList(Long uid) {
return String.format(CACHE_KEY_TOKEN_LIST, uid);
}
/**
* 图片验证码 缓存key
**/
public static final String CACHE_KEY_IMG_CODE = "img_code_%s";
public static String getCacheKeyImgCode(String imgToken) {
return String.format(CACHE_KEY_IMG_CODE, imgToken);
}
/**
* 短信验证码 缓存key
**/
public static final String CACHE_KEY_SMS_CODE = "sms_code_%s";
public static String getCacheKeySmsCode(String phone) {
return String.format(CACHE_KEY_SMS_CODE, phone);
}
/**
* wxjava redis缓存key前缀
**/
public static final String CACHE_KEY_WX_JAVA = "WX_JAVA_REDIS_";
/**
* 登录防穷举 缓存key
**/
public static final String CACHE_KEY_LOGIN_ERR = "LOGIN_ERR_%s_%s";
public static String getCacheKeyLoginErr(String sysType, String username) {
return String.format(CACHE_KEY_LOGIN_ERR, sysType, username);
}
/**
* 扫码登录 二维码 缓存key
**/
public static final String CACHE_KEY_LOGIN_QRCODE = "JEEPAY_LOGIN_QR_%s";
public static String getCacheKeyLoginQrcode(String uuid) {
return String.format(CACHE_KEY_LOGIN_QRCODE, uuid);
}
/**
* T+N时间 缓存key 参数dateStr-日期YYYY-MM-DD dayTN-(T+N的N天)
**/
public static final String CACHE_KEY_DATE_TN_PREFIX = "CACHE_KEY_DATE_TN_";
public static String getCacheKeyDateTn(String dateStr, int dayTN) {
return String.format(CACHE_KEY_DATE_TN_PREFIX + "%s_%s", dateStr, dayTN);
}
/**
* 百度语音合成token 缓存key
**/
public static final String BAIDU_TOKEN_CACHE_KEY = "baidu_bce_token";
public static final long BAIDU_TOKEN_TIME = 29; // 单位:天
/**
* 品生云喇叭token 缓存key
**/
public static final String PINSHENG_TOKEN_CACHE_KEY = "ps_token";
public static final long PINSHENG_TOKEN_TIME = 3600; // 单位:秒
/**
* 回调URL的格前缀
*/
public static final String PAY_RETURNURL_FIX_ONLY_JUMP_PREFIX = "ONLYJUMP_";
public static final String PAY_RETURNURL_FIX_MCHAPP_PREFIX = "JEEPAYMCHAPP_";
public static final String PAY_RETURNURL_FIX_ISV_PREFIX = "JEEPAYISV_";
public static String parsePayReturnUrlFix(String urlOrderId, String prefixStr) {
if (StringUtils.isAnyEmpty(urlOrderId, prefixStr)) {
return null;
}
if (urlOrderId.indexOf(prefixStr) != 0) {
return null;
}
return urlOrderId.substring(prefixStr.length());
}
public static final class PRODUCT_API_CODE {
// 安全发
public static final String AQF = "API_ANQUANFA_CP_PAY";
// 与通道关联的关系
public static final Map<String, String> CONN_MAP = new HashMap<>();
static {
CONN_MAP.put(IF_CODE.ALIAQF, AQF);
}
}
/**
* 登录认证类型
**/
public interface AUTH_TYPE {
byte LOGIN_USER_NAME = 1; //登录用户名
byte TELPHONE = 2; //手机号
byte EMAIL = 3; //邮箱
byte WX_UNION_ID = 10; //微信unionId
byte WX_MINI = 11; //微信小程序
byte WX_MP = 12; //微信公众号
byte QQ = 20; //QQ
}
//菜单类型
public interface ENT_TYPE {
String MENU_LEFT = "ML"; //左侧显示菜单
String MENU_OTHER = "MO"; //其他菜单
String PAGE_OR_BTN = "PB"; //页面 or 按钮
}
@Getter
@AllArgsConstructor
public enum IfCode {
YSPAY("yspay"),
KQPAY("kqpay"),
LKLSPAY("lklspay"),
LKLSB2BPAY("lklsb2bpay"),
SXFPAY("sxfpay"),
RYXPAY("ryxpay"),
DGPAY("dgpay"),
ZFTPAY("zftpay")
;
private final String value;
public static IfCode get(String value) {
for (IfCode ifCode : values()) {
if (ifCode.value.equals(value)) {
return ifCode;
}
}
return null;
}
}
//接口类型
public interface IF_CODE {
String ALIPAY = "alipay"; // 支付宝官方支付
String WXPAY = "wxpay"; // 微信官方支付
String YSFPAY = "ysfpay"; // 云闪付开放平台
String XXPAY = "xxpay"; // 小新支付
String ADAPAY = "adapay"; // 汇付支付
String SHENGPAY = "shengpay"; // 盛付通支付
String UNIONPAY = "unionpay"; // 银联支付
String ZFTPAY = "zftpay"; // 支付宝直付通
String SFTPAY = "sftpay"; // 微信收付通
String SANDPAY = "sandpay"; // 杉德支付
String PPPAY = "pppay"; // Paypal 支付
String HMPAY = "hmpay"; // 河马[杉德]支付
String FUIOUPAY = "fuioupay"; // 富友支付
String LKLPAY = "lklpay"; // 拉卡拉支付
String LKLSPAY = "lklspay"; // 拉卡拉saas支付
String LKLSB2BPAY = "lklsb2bpay"; // 拉卡拉saas支付
String PFPAY = "pfpay"; // 浦发银行
String FBPAY = "fbpay"; // 付呗支付
String DGPAY = "dgpay"; // 斗拱[汇付]支付
String UTMPAY = "utmpay"; // 支付
String SQBPAY = "sqbpay"; // 收钱吧支付
String YSPAY = "yspay"; // 银盛支付
String JOINPAY = "joinpay"; // 汇聚支付
String RYXPAY = "ryxpay"; // 瑞银信支付
String ALLINPAY = "allinpay"; // 通联支付
String MBPAY = "mbpay"; // 米花支付
String TERPAY = "terpay"; // 国通星驿支付
String PMPAY = "pmpay"; // PayerMax支付
String UMPAY = "umpay"; // 联动优势
String CCBPAY = "ccbpay"; // 建行支付
String CLOUDPAY = "cloudpay"; // 支付宝云支付
String HKPAY = "hkpay"; // 海科融通支付
String HNAPAY = "hnapay"; // 新生支付
String BCMPAY = "bcmpay"; // 交行支付
String SUMAPAY = "sumapay"; // 丰付支付
String ICBCPAY = "icbcpay"; // 工行支付
String EASYPAY = "easypay"; // 易生支付
String LMSPAY = "lmspay"; // 立码收
String LESHUAPAY = "leshuapay"; // 乐刷
String ALIAQF = "aliaqf"; // 支付宝安全发
String SXFPAY = "sxfpay"; // 随行付
String CIBPAY = "CIBPAY"; // 兴业银行
String EPSPAY = "epspay"; // 易票联
String DEMOMOCKPAY = "demomockpay"; // 【模拟支付】
String UMHSPAY = "umhspay"; // 联动惠商
String KDBPAY = "kdbpay"; // 开店宝
/**
* 快钱支付
*/
String KQPAY = "kqpay";
String SYBPAY = "sybpay";
/**
* 福禄
*/
String FLPAY = "flpay";
}
public interface SETTLEMENT_TYPE {
String T1 = "T1";
String D1 = "D1";
String D0 = "D0";
}
//支付方式代码
public interface PAY_WAY_CODE {
// 特殊支付方式
String WEB_CASHIER = "WEB_CASHIER"; // ( web端的统一收银台支付 )
String AUTO_POS = "AUTO_POS"; // ( 智能pos收款 )
String TRANSFER = "TRANSFER"; // ( 转账 )
String QR_CASHIER = "QR_CASHIER"; // ( 通过二维码跳转到收银台完成支付, 已集成获取用户ID的实现。 )
String AUTO_BAR = "AUTO_BAR"; // 条码聚合支付(自动分类条码类型)
String OUT_TRADE = "OUT_TRADE"; // 外部订单
String ALI_BAR = "ALI_BAR"; //支付宝条码支付
String ALI_JSAPI = "ALI_JSAPI"; //支付宝服务窗支付
String ALI_LITE = "ALI_LITE"; //支付宝小程序支付
String ALI_APP = "ALI_APP"; //支付宝 app支付
String ALI_PC = "ALI_PC"; //支付宝 电脑网站支付
String ALI_WAP = "ALI_WAP"; //支付宝 wap支付
String ALI_QR = "ALI_QR"; //支付宝 二维码付款
String YSF_BAR = "YSF_BAR"; //云闪付条码支付
String YSF_JSAPI = "YSF_JSAPI"; //云闪付服务窗支付
String ALI_H5 = "ALI_H5"; //微信H5支付
String WX_JSAPI = "WX_JSAPI"; //微信jsapi支付
String WX_LITE = "WX_LITE"; //微信小程序支付
String WX_BAR = "WX_BAR"; //微信条码支付
String WX_H5 = "WX_H5"; //微信H5支付
String WX_NATIVE = "WX_NATIVE"; //微信扫码支付
String WX_APP = "WX_APP"; //微信扫码支付
String UP_APP = "UP_APP"; // 银联App支付
String UP_WAP = "UP_WAP"; // 银联手机网站支付
String UP_QR = "UP_QR"; // 银联二维码(主扫)
String UP_BAR = "UP_BAR"; // 银联二维码(被扫)
String UP_B2B = "UP_B2B"; // 银联企业网银支付
String UP_PC = "UP_PC"; // 银联网关支付
String UP_JSAPI = "UP_JSAPI"; // 银联JS支付
String PP_PC = "PP_PC"; // Paypal 支付
String SAND_H5 = "SAND_H5"; // 杉德H5收银台
String CASHIER = "CASHIER"; // 渠道收银台
String BANK_QUICK = "BANK_QUICK"; // 银联快捷
String BANK_B2C = "BANK_B2C"; // 网银B2C
String DCEP_BAR = "DCEP_BAR"; // 数字人民币条码支付
String DCEP_QR = "DCEP_QR"; // 数字人民币二维码支付
String KQ_H5 = "KQ_H5"; // 快钱
String D1 = "D1"; // D1垫资费, 部分通道有
String D0 = "D0"; // D0垫资费, 部分通道有
String SCAN = "SCAN"; // 线上费率
}
//支付数据包 类型
public interface PAY_DATA_TYPE {
String PAY_URL = "payurl"; //跳转链接的方式 redirectUrl
String FORM = "form"; //表单提交
String WX_APP = "wxapp"; //微信app参数
String ALI_APP = "aliapp"; //支付宝app参数
String YSF_APP = "ysfapp"; //云闪付app参数
String CODE_URL = "codeUrl"; //二维码URL
String CODE_IMG_URL = "codeImgUrl"; //二维码图片显示URL
String NONE = "none"; //无参数
// String QR_CONTENT = "qrContent"; //二维码实际内容
}
// 支付方式 分类字典
public interface PAY_WAY_CODE_TYPE {
String WECHAT = "WECHAT";
String ALIPAY = "ALIPAY";
String YSFPAY = "YSFPAY";
String UNIONPAY = "UNIONPAY";
String DCEPPAY = "DCEPPAY";
String OTHER = "OTHER";
String SCAN = "SCAN";
}
// 支付方式分类名称
public static final Map<String, String> PAY_WAY_CODE_TYPE_MAP = new HashMap<>();
static {
PAY_WAY_CODE_TYPE_MAP.put(PAY_WAY_CODE_TYPE.ALIPAY, "支付宝");
PAY_WAY_CODE_TYPE_MAP.put(PAY_WAY_CODE_TYPE.WECHAT, "微信");
PAY_WAY_CODE_TYPE_MAP.put(PAY_WAY_CODE_TYPE.YSFPAY, "云闪付");
PAY_WAY_CODE_TYPE_MAP.put(PAY_WAY_CODE_TYPE.UNIONPAY, "银联");
PAY_WAY_CODE_TYPE_MAP.put(PAY_WAY_CODE_TYPE.DCEPPAY, "数字人民币");
PAY_WAY_CODE_TYPE_MAP.put(PAY_WAY_CODE_TYPE.OTHER, "其他");
PAY_WAY_CODE_TYPE_MAP.put(PAY_WAY_CODE_TYPE.SCAN, "线上");
}
// 智能POS 支付方式
public interface AUTO_POS_PAY_TYPE {
String CARD = "CARD"; // 银行卡
String SCAN = "SCAN"; // 扫一扫
String QRCODE = "QRCODE"; // 聚合码
}
// 智能POS 支付渠道
public interface AUTO_POS_PAY_CHANNEL {
String WECHAT = "WECHAT"; // 微信
String ALIPAY = "ALIPAY"; // 支付宝
String UNIONPAY = "UNIONPAY"; // 银联
String QR_CASHIER = "QR_CASHIER"; // 聚合码
String DCEP = "DCEPPAY"; // 数字货币
}
//接口版本
public interface PAY_IF_VERSION {
String WX_V2 = "V2"; //微信接口版本V2
String WX_V3 = "V3"; //微信接口版本V3
}
// 设备厂商
public interface DEVICE_PROVIDER {
String BSJ = "bsj"; // 博实结
String ZGWL = "zgwl"; // 智谷物联
String PS = "ps"; // 品生
String FE = "fe"; // 飞鹅
String ZW = "zw"; // 智网
String JSD = "jsd"; // 金士盾
String LLZN = "llzn"; // 零零智能
String YLY = "yly"; // 易联云
String LKLS = "lkls"; // 拉卡拉
}
// 统计接口类型
public interface STATISTIC_TYPE {
String MCH = "mch"; // 商户
String AGENT = "agent"; // 服务商
String ISV = "isv"; // 服务商
String CHANNEL = "channel"; // 通道
String TRANSACTION = "transaction"; // 报表
String STORE = "store"; // 门店
String WAY_CODE = "wayCode"; // 支付方式
String WAY_CODE_TYPE = "wayCodeType"; // 支付类型
String DEVICE = "device"; // 设备
}
/**
* 代码(项目)层面 全部的系统定义, 需要注入到对应的bean中
**/
public interface CODE_SYS_NAME_SET {
String JEEPAY_MANAGER = "MANAGER";
String JEEPAY_MERCHANT = "MERCHANT";
String JEEPAY_AGENT = "AGENT";
String JEEPAY_STORE = "STORE";
String JEEPAY_PAYMENT = "PAYMENT";
}
/**
* 商户通知类型的枚举值
**/
public interface NOTIFY_POST_TYPE {
String POST_QUERYSTRING = "POST_QUERYSTRING";
String POST_BODY = "POST_BODY";
String POST_JSON = "POST_JSON";
}
/**
* 商户自调用接口
*/
public interface MCH_APP_API_ENUM {
String API_PAY_ORDER = "API_PAY_ORDER"; // 统一下单
String API_PAY_ORDER_QUERY = "API_PAY_ORDER_QUERY"; // 对分账用户的渠道余额发起提现
String API_PAY_ORDER_CLOSE = "API_PAY_ORDER_CLOSE"; // 支付订单关闭
String API_CHANNEL_USER = "API_CHANNEL_USER"; // 获取渠道用户ID
String API_REFUND_ORDER = "API_REFUND_ORDER"; // 发起支付退款
String API_REFUND_ORDER_QUERY = "API_REFUND_ORDER_QUERY"; // 查询退款订单
String API_TRANS_ORDER = "API_TRANS_ORDER"; // 发起转账订单
String API_TRANS_ORDER_QUERY = "API_TRANS_ORDER_QUERY"; // 查询转账订单
String API_TRANS_BALANCE_QUERY = "API_TRANS_BALANCE_QUERY"; // 查询转账可用余额
String API_DIVISION_BIND = "API_DIVISION_BIND"; // 绑定分账用户
String API_DIVISION_EXEC = "API_DIVISION_EXEC"; // 发起订单分账
String API_DIVISION_CHANNEL_BALANCE = "API_DIVISION_CHANNEL_BALANCE"; // 查询分账用户可用余额
String API_DIVISION_CHANNEL_CASHOUT = "API_DIVISION_CHANNEL_CASHOUT"; // 对分账用户的渠道余额发起提现
}
public interface MCH_APP_API_ENUM_V2 {
String APP_PAY = "API_APP_PAY"; // APP支付
String H5_PAY = "API_H5_PAY"; // H5支付 手机
String JSAPI_PAY = "API_JSAPI_PAY"; // 公众号/生活号支付
String APPLET_PAY = "API_APPLET_PAY"; // 小程序支付
String MICRO_PAY = "API_MICRO_PAY"; // 反扫支付
String SCAN_PAY = "API_SCAN_PAY"; // (聚合码)电脑网站支付
String CASHIER_PAY = "API_CASHIER_PAY"; // 聚合收银台
}
/**
* 会员头像默认值
**/
public static final List<String> MEMBER_AVATAR_ICON = new ArrayList<>();
static {
MEMBER_AVATAR_ICON.add("http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/m-photo-0.svg");
MEMBER_AVATAR_ICON.add("http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/m-photo-1.svg");
MEMBER_AVATAR_ICON.add("http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/m-photo-2.svg");
MEMBER_AVATAR_ICON.add("http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/m-photo-3.svg");
MEMBER_AVATAR_ICON.add("http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/m-photo-4.svg");
MEMBER_AVATAR_ICON.add("http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/m-photo-5.svg");
MEMBER_AVATAR_ICON.add("http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/m-photo-6.svg");
}
/**
* 短信配置类型
*/
public interface SMS_TYPE_API_ENUM {
String TYPE_AUTH = "auth"; // 登录验证码
String TYPE_REGISTER = "register"; // 注册验证码
String TYPE_RETRIEVE = "retrieve"; // 找回密码验证码
String TYPE_ACCOUNT_OPEN = "accountOpen"; // 账号开通
String TYPE_MBR_TEL_BIND = "mbrTelBind"; // 会员手机号绑定
String TYPE_ACCOUNT_BALANCE = "accountBalance"; //账户余额
}
/**
* 短信厂商配置类型
*/
public interface SMS_PROVIDER_TYPE_API_ENUM {
/**
* 模拟测试
*/
String SMS_PROVIDE_KEY_MOCKTEST = "mocktest";
/**
* 阿里大于
*/
String SMS_PROVIDE_KEY_ALIYUNDY = "aliyundy";
/**
* 计全短信
*/
String SMS_PROVIDE_KEY_JEEPAYDX = "jeepaydx";
/**
* 聚合数据短信
*/
String SMS_PROVIDE_KEY_JUHEDX = "juhedx";
}
/**
* 通知类型
*/
public interface OpenMsgType {
/**
* 交易通知
*/
String TRADE_MSG_TYPE = "sft.trade.notify";
/**
* 退款通知
*/
String REFUND_MSG_TYPE = "sft.refund.notify";
/**
* 分账通知
*/
String DIVISION_MSG_TYPE = "sft.division.notify";
}
@Getter
@AllArgsConstructor
public enum DrType{
DEBIT("00","借记卡"),
CREDIT("01","贷记卡"),
BALANCE("02","余额"),
TOKIO("03","花呗"),
DCEP("04","数字人民币"),
OTHER("99","其他");
private final String type;
private final String desc;
}
@Getter
@AllArgsConstructor
public enum AccountOperateType{
CHARGE((byte)0,"充值"),
CASH((byte)1,"提现"),
TRANSFER((byte)2,"转账"),
REFUND((byte)3,"退款");
private final Byte type;
private final String desc;
public static AccountOperateType getVal(byte value){
AccountOperateType[] values = values();
for (AccountOperateType val:values) {
if(val.getType() == value){
return val;
}
}
return CHARGE;
}
}
/**
* 支付状态: 0-订单生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭 7,退款中
*/
@Getter
@AllArgsConstructor
public enum OpenOrderState{
INIT((byte)0,"INIT","订单初始化"),
AWAIT((byte)1,"TRADE_AWAIT","等待用户付款"),
SUCCESS((byte)2,"TRADE_SUCCESS","成功"),
FAIL((byte)3,"TRADE_FAIL","失败"),
CANCEL((byte)4,"TRADE_CANCEL","交易取消"),
REFUND((byte)5,"TRADE_REFUND","订单退款"),
CLOSE((byte)6,"TRADE_CLOSE","订单关闭"),
REFUND_ING((byte)7,"REFUND_ING","退款中");
private final Byte value;
private final String code;
private final String desc;
public static OpenOrderState getVal(byte value){
OpenOrderState[] values = values();
for (OpenOrderState val:values) {
if(val.getValue() == value){
return val;
}
}
return AWAIT;
}
}
@Getter
@AllArgsConstructor
public enum OpenRefundState{
INIT((byte)0,"INIT","订单初始化"),
ING((byte)1,"ING","退款中"),
SUCCESS((byte)2,"SUCCESS","退款成功"),
FAIL((byte)3,"FAIL","退款失败"),
CLOSE((byte)4,"CLOSE","退款关闭");
private final Byte value;
private final String code;
private final String desc;
public static OpenRefundState getVal(byte value){
OpenRefundState[] values = values();
for (OpenRefundState val:values) {
if(val.getValue() == value){
return val;
}
}
return INIT;
}
}
}

View File

@@ -0,0 +1,18 @@
package com.jeequan.jeepay.core.constants;
/*
* 渠道商户类型
*
* @author zx
*
* @date 2023/4/7 12:07
*/
public enum ChannelMchIdTypeEnum {
// 服务商机构号
ISV_NO,
// 子商户号
MCH_NO,
}

View File

@@ -0,0 +1,20 @@
package com.jeequan.jeepay.core.constants;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ConstWord {
public static final String CONFIG_MODE = "configMode";
public static final String IF_CODE = "ifCode";
public static final String ISV_NO = "isvNo";
public static final String APP_ID = "appId";
public static final String INFO_ID = "infoId";
public static final String INFO_TYPE = "infoType";
}

View File

@@ -0,0 +1,29 @@
package com.jeequan.jeepay.core.constants;
/*
* 脱敏类型
*
* @author zx
*
* @date 2023/4/7 12:07
*/
public enum DesensitizedTypeEnum {
//中文名
CHINESE_NAME,
//身份证号
ID_CARD,
//座机号
FIXED_PHONE,
//手机号
MOBILE_PHONE,
//地址
ADDRESS,
//电子邮件
EMAIL,
//密码
PASSWORD,
//银行卡
BANK_CARD
}

View File

@@ -0,0 +1,361 @@
package com.jeequan.jeepay.core.ctrls;
import cn.hutool.core.text.CharSequenceUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.core.beans.RequestKitBean;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.BaseModel;
import com.jeequan.jeepay.core.utils.DateKit;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* 抽象公共Ctrl
*
* @author terrfly
* @date 2020/02/18 17:28
*/
public abstract class AbstractCtrl {
protected static final Logger logger = LoggerFactory.getLogger(AbstractCtrl.class);
private static final String PAGE_INDEX_PARAM_NAME = "pageNumber"; //分页页码 参数名
private static final String PAGE_SIZE_PARAM_NAME = "pageSize"; //分页条数 参数名
private static final int DEFAULT_PAGE_INDEX = 1; // 默认页码: 第一页
private static final int DEFAULT_PAGE_SIZE = 20; // 默认条数: 20
private static final String SORT_FIELD_PARAM_NAME = "sortField"; //排序字段
private static final String SORT_ORDER_FLAG_PARAM_NAME = "sortOrder"; // 排序正序, 倒序标志
@Autowired
protected HttpServletRequest request; //自动注入request
@Autowired
protected HttpServletResponse response; //自动注入response
@Autowired
protected RequestKitBean requestKitBean;
/**
* 获取json格式的请求参数
**/
protected JSONObject getReqParamJSON() {
return requestKitBean.getReqParamJSON();
}
/**
* 获取页码
**/
protected int getPageIndex() {
Integer pageIndex = getReqParamJSON().getInteger(PAGE_INDEX_PARAM_NAME);
if (pageIndex == null) {
return DEFAULT_PAGE_INDEX;
}
return pageIndex;
}
/**
* 获取条数, 默认不允许查询全部数据
**/
protected int getPageSize() {
return getPageSize(false);
}
/**
* 获取条数, 加入条件:是否允许获取全部数据
**/
protected int getPageSize(boolean allowQueryAll) {
Integer pageSize = getReqParamJSON().getInteger(PAGE_SIZE_PARAM_NAME);
if (allowQueryAll && pageSize != null && pageSize == -1) {
return Integer.MAX_VALUE; // -1代表获取全部数据查询int最大值的数据
}
if (pageSize == null || pageSize < 0) {
return DEFAULT_PAGE_SIZE;
}
return pageSize;
}
/**
* 获取Ipage分页信息, 默认不允许获取全部数据
**/
protected <T> Page<T> getIPage() {
return new Page<>(getPageIndex(), getPageSize());
}
/**
* 获取Ipage分页信息, 加入条件:是否允许获取全部数据
**/
protected <T> Page<T> getIPage(boolean allowQueryAll) {
return new Page<>(getPageIndex(), getPageSize(allowQueryAll));
}
/**
* 获取排序字段 MutablePair<是否正序, 排序字段>
**/
protected MutablePair<Boolean, String> getSortInfo() {
String sortField = getReqParamJSON().getString(SORT_FIELD_PARAM_NAME);
String sortOrderFlag = getReqParamJSON().getString(SORT_ORDER_FLAG_PARAM_NAME);
if (StringUtils.isAllEmpty(sortField, sortField)) {
return null;
}
return MutablePair.of("ascend".equalsIgnoreCase(sortOrderFlag), CharSequenceUtil.toUnderlineCase(sortField).toLowerCase());
}
/**
* 获取请求参数值 [ T 类型 ], [ 非必填 ]
**/
protected <T> T getVal(String key, Class<T> cls) {
return getReqParamJSON().getObject(key, cls);
}
/**
* 获取请求参数值 [ T 类型 ], [ 必填 ]
**/
protected <T> T getValRequired(String key, Class<T> cls) {
T value = getVal(key, cls);
if (ObjectUtils.isEmpty(value)) {
throw new BizException(ApiCodeEnum.PARAMS_ERROR, genParamRequiredMsg(key));
}
return value;
}
/**
* 获取请求参数值 [ T 类型 ], [ 如为null返回默认值 ]
**/
protected <T> T getValDefault(String key, T defaultValue, Class<T> cls) {
T value = getVal(key, cls);
if (ObjectUtils.isEmpty(value)) {
return defaultValue;
}
return value;
}
/**
* 获取请求参数值 String 类型相关函数
**/
protected String getValString(String key) {
return getVal(key, String.class);
}
protected String getValStringRequired(String key) {
return getValRequired(key, String.class);
}
protected String getValStringDefault(String key, String defaultValue) {
return getValDefault(key, defaultValue, String.class);
}
/**
* 获取请求参数值 Byte 类型相关函数
**/
protected Byte getValByte(String key) {
return getVal(key, Byte.class);
}
protected Byte getValByteRequired(String key) {
return getValRequired(key, Byte.class);
}
protected Byte getValByteDefault(String key, Byte defaultValue) {
return getValDefault(key, defaultValue, Byte.class);
}
/**
* 获取请求参数值 Integer 类型相关函数
**/
protected Integer getValInteger(String key) {
return getVal(key, Integer.class);
}
protected Integer getValIntegerRequired(String key) {
return getValRequired(key, Integer.class);
}
protected Integer getValIntegerDefault(String key, Integer defaultValue) {
return getValDefault(key, defaultValue, Integer.class);
}
/**
* 获取请求参数值 Long 类型相关函数
**/
protected Long getValLong(String key) {
return getVal(key, Long.class);
}
protected Long getValLongRequired(String key) {
return getValRequired(key, Long.class);
}
protected Long getValLongDefault(String key, Long defaultValue) {
return getValDefault(key, defaultValue, Long.class);
}
/**
* 获取请求参数值 BigDecimal 类型相关函数
**/
protected BigDecimal getValBigDecimal(String key) {
return getVal(key, BigDecimal.class);
}
protected BigDecimal getValBigDecimalRequired(String key) {
return getValRequired(key, BigDecimal.class);
}
protected BigDecimal getValBigDecimalDefault(String key, BigDecimal defaultValue) {
return getValDefault(key, defaultValue, BigDecimal.class);
}
/**
* 获取对象类型
**/
protected <T> T getObject(Class<T> clazz) {
JSONObject params = getReqParamJSON();
T result = params.toJavaObject(clazz);
if (result instanceof BaseModel) { //如果属于BaseModel, 处理apiExtVal
JSONObject resultTemp = (JSONObject) JSON.toJSON(result);
for (Map.Entry<String, Object> entry : params.entrySet()) { //遍历原始参数
if (!resultTemp.containsKey(entry.getKey())) {
((BaseModel) result).addExt(entry.getKey(), entry.getValue());
}
}
}
return result;
}
/**
* 生成参数必填错误信息
**/
private String genParamRequiredMsg(String key) {
return "参数" + key + "必填";
}
/**
* 校验参数值不能为空
*/
protected void checkRequired(String... keys) {
for (String key : keys) {
String value = getReqParamJSON().getString(key);
if (StringUtils.isEmpty(value)) {
throw new BizException(ApiCodeEnum.PARAMS_ERROR, genParamRequiredMsg(key));
}
}
}
/**
* 得到前端传入的金额元,转换成长整型分
**/
public Long getRequiredAmountL(String name) {
String amountStr = getValStringRequired(name); // 前端填写的为元,可以为小数点2位
return new BigDecimal(amountStr.trim()).multiply(new BigDecimal(100)).longValue();
}
/**
* 得到前端传入的金额元,转换成长整型分 (非必填)
**/
public Long getAmountL(String name) {
String amountStr = getValString(name); // 前端填写的为元,可以为小数点2位
if (StringUtils.isEmpty(amountStr)) {
return null;
}
return new BigDecimal(amountStr.trim()).multiply(new BigDecimal(100)).longValue();
}
/**
* 处理参数中的金额(将前端传入金额元转成分)
* modify: 20181206 添加JSON对象中的对象属性转换为分 格式[xxx.xxx]
*/
public void handleParamAmount(String... names) {
for (String name : names) {
String amountStr = getValString(name); // 前端填写的为元,可以为小数点2位
if (StringUtils.isNotBlank(amountStr)) {
Long amountL = new BigDecimal(amountStr.trim()).multiply(new BigDecimal(100)).longValue(); // // 转成分
if (!name.contains(".")) {
getReqParamJSON().put(name, amountL);
continue;
}
getReqParamJSON().getJSONObject(name.substring(0, name.indexOf("."))).put(name.substring(name.indexOf(".") + 1), amountL);
}
}
}
/**
* 获取查询的时间范围
*
* @return
*/
protected Date[] getQueryDateRange() {
return DateKit.getQueryDateRange(getReqParamJSON().getString("queryDateRange")); //默认参数为 queryDateRange
}
/**
* 请求参数转换为map格式
**/
public Map<String, Object> request2payResponseMap(HttpServletRequest request, String[] paramArray) {
Map<String, Object> responseMap = new HashMap<>();
for (String key : paramArray) {
String v = request.getParameter(key);
if (v != null) {
responseMap.put(key, v);
}
}
return responseMap;
}
/**
* 将上传的文件进行保存 - 公共函数
**/
protected void saveFile(MultipartFile file, String savePath) throws Exception {
File saveFile = new File(savePath);
//如果文件夹不存在则创建文件夹
File dir = saveFile.getParentFile();
if (!dir.exists()) {
dir.mkdirs();
}
file.transferTo(saveFile);
}
/**
* 获取客户端ip地址
**/
public String getClientIp() {
return requestKitBean.getClientIp();
}
public String getUserAgent() {
String userAgent = request.getHeader("User-Agent");
return StringUtils.isNotEmpty(userAgent) ? userAgent : "未知";
}
/**
* 贴牌获取请求域名
**/
public String getdomainName() {
return requestKitBean.getdomainName();
}
}

View File

@@ -0,0 +1,30 @@
package com.jeequan.jeepay.core.entity;
import lombok.Data;
/**
* TODO
* 提现信息
* @author crystal
* @date 2023/12/20 16:15
*/
@Data
public class AccountCashInfo {
private Long cashAmt;
private String settleName;
private String settleNo;
private String bankCardAreaCode;
private String bankCardAreaName;
private String bankName;
private String bankMobile;
private String settleCard;
}

View File

@@ -0,0 +1,150 @@
package com.jeequan.jeepay.core.entity;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.exception.BizException;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
/**
* TODO
*
* @author crystal
* @date 2023/12/11 16:23
*/
@Data
public class AccountOperate {
/**
* 最小充值金额
*/
public static final Long MIN_RECHARGE_AMT = 10000L;
/**
* 最大充值充值
*/
public static final Long MAX_RECHARGE_AMT = 5000000L;
/**
* 扫码入账比例 0.006 的手续费比例
*/
public static final BigDecimal SCAN_REALITY_SCALE = BigDecimal.valueOf(0.994);
/**
* 账户号
*/
private String accountNo;
/**
* 金额
*/
private Long amount;
/**
* 实际金额
*/
private Long finalAmt;
/**
* 变动方式 -1:提现驳回 0扫码充值 1对公转账 2账户提现 3:一般户退款
*/
private Byte changeMethod;
/**
* 变动类型 0充值 1提现 2转账 3退款
*/
private Byte changeType;
/**
* 收款商户号
*/
private String mchExtNo;
/**
*状态
*/
private Byte state;
/**
* 打款类型
*/
private Byte mark;
/**
* 订单号
*/
private String orderId;
/**
* 是否修改账户 默认不修改
*/
private Boolean isUpdateAccount = false;
/**
* 备注
*/
private String remark;
/**
* 付款标识
*/
private String ifCode;
/**
* 改变金额
*/
private Long changeAmt;
/**
* 扩展参数
*/
private JSONObject extra;
public AccountOperate(String accountNo, Long amount,byte changeType,byte changeMethod,String orderId,String remark) {
this.accountNo = accountNo;
this.amount = amount;
this.changeType = changeType;
this.changeMethod = changeMethod;
this.orderId = orderId;
this.remark = remark;
this.finalAmt = amount;
}
// public AccountOperate(String accountNo, Long amount,byte changeType,byte changeMethod) {
// this.accountNo = accountNo;
// this.amount = amount;
// this.chaneType = changeType;
// this.changeMethod = changeMethod;
// }
public AccountOperate(String orderId,Boolean isUpdateAccount,Byte state) {
this.orderId = orderId;
this.isUpdateAccount = isUpdateAccount;
this.state = state;
}
public void preRechargeCheck() {
if(this.getChangeMethod() == 0){
if(this.getAmount() < MIN_RECHARGE_AMT || this.getAmount() > MAX_RECHARGE_AMT){
throw new BizException("充值金额范围区间为:"+MIN_RECHARGE_AMT / 100+"-" + MAX_RECHARGE_AMT / 100 +"元之间");
}
}
}
public void preCheck(){
if(StringUtils.isEmpty(this.getOrderId())){
throw new BizException("流水号不能为空");
}
}
public void preAccountCheck() {
preCheck();
if(StringUtils.isEmpty(this.getAccountNo())){
throw new BizException("账户编号不能为空");
}
if(this.getAmount() == null){
throw new BizException("金额不能为空");
}
}
}

View File

@@ -0,0 +1,51 @@
package com.jeequan.jeepay.core.entity;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
* TODO
* 账户提醒规则
* @author crystal
* @date 2023/12/18 10:56
*/
@Data
public class AccountRuleExt {
/**
* 邮箱
*/
public static final String EMAIL = "email";
/**
* 手机短信
*/
public static final String PHONE = "phone";
/**
* 站内信
*/
public static final String MAIL = "mail";
/**
* 金额
*/
private BigDecimal amount;
/**
* 提醒频率 6 / 12 /24
*/
private Integer interval;
/**
* 类型
*/
private List<String> typeList;
/**
* 接收人信息
*/
private List<JSONObject> receiveList;
}

View File

@@ -0,0 +1,188 @@
package com.jeequan.jeepay.core.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
@Data
@Accessors(chain = true)
public class CashoutRecord extends BaseModel {
private static final long serialVersionUID=1L;
/** 提现类型 佣金提现 **/
public static final byte SETT_TYPE_COMM = 1;
/** 提现状态 结算状态: 1-审核中, 2-审核失败, 3-结算中, 4-结算成功, 5-结算失败 **/
public static final byte CASHOUT_STATE_AUDIT_ING = 1;
public static final byte CASHOUT_STATE_AUDIT_FAIL = 2;
public static final byte CASHOUT_STATE_SETT_ING = 3;
public static final byte CASHOUT_STATE_SETT_SUCCESS = 4;
public static final byte CASHOUT_STATE_SETT_FAIL = 5;
/**
* 提现记录ID
*/
@TableId(value = "rid", type = IdType.AUTO)
private Long rid;
/**
* 服务商号等
*/
private String infoId;
/**
* 系统类型: 参考SYS_ROLE_TYPE
*/
private String infoType;
/**
* 名称快照
*/
private String infoName;
/**
* 申请金额,单位分
*/
private Long applyAmount;
/**
* 手续费金额,单位分
*/
private Long settFeeAmount;
/**
* 手续费计算公式(快照)
*/
private String settFeeRule;
/**
* 最终结算金额 (申请-手续费), 单位分
*/
private Long settAmount;
/**
* 结算账户类型: WX_CASH-微信零钱; ALIPAY_CASH-支付宝转账; BANK_CARD-银行卡
*/
private String settAccountType;
/**
* 结算账户账号
*/
private String settAccountNo;
/**
* 结算账户姓名
*/
private String settAccountName;
/**
* 结算账户开户行名称
*/
private String settAccountBank;
/**
* 开户行支行名称
*/
private String settAccountSubBank;
/**
* 结算账户联系人手机号(一般为服务商手机号)
*/
private String settAccountTelphone;
/**
* 联系人姓名
*/
private String contactName;
/**
* 用户提现备注
*/
private String applyRemark;
/**
* 结算备注[系统生成]
*/
private String settInfo;
/**
* 结算状态: 1-审核中, 2-审核失败, 3-结算中, 4-结算成功, 5-结算失败
*/
private Byte state;
/**
* 结算凭证图片
*/
private String settCertImg;
/**
* 打款凭证(运营平台)
*/
private String transferCertImg;
/**
* 提现类型: 1-佣金提现
*/
private Byte settType;
/**
* 发起转账的自营应用ID
*/
private String transferMchAppId;
/**
* 转账系统订单号
*/
private String transferOrderId;
/**
* 转账接口类型
*/
private String transferIfCode;
/**
* 自营商户费率费用
*/
private Long transferPlatformMchfeeAmount;
/**
* 平台真实成本费用( 来自转账订单数据 = 自营商户费率费用 - 平台利润
*/
private Long transferPlatformCostAmount;
/**
* 审核时间
*/
private Date auditTime;
/**
* 审核备注
*/
private String auditRemark;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
@TableField(exist = false)
private String idCard;
@TableField(exist = false)
private String bankPhone;
}

View File

@@ -0,0 +1,142 @@
package com.jeequan.jeepay.core.entity;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 提现结算记录表
* </p>
*
* @author [mybatis plus generator]
* @since 2022-11-09
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
public class ChannelAccountCashoutRecord extends BaseModel implements Serializable {
private static final long serialVersionUID=1L;
/** 提现状态 结算状态: 0-提现单创建, 1-提现中, 2-提现成功, 3-提现失败 **/
public static final byte CASHOUT_STATE_CREATE = 0;
public static final byte CASHOUT_STATE_ING = 1;
public static final byte CASHOUT_STATE_SUCCESS = 2;
public static final byte CASHOUT_STATE_FAIL = 3;
/** 提现来源 task-定时任务 order-订单 **/
public static final String CASHOUT_FROM_TASK = "task";
public static final String CASHOUT_FROM_ORDER = "order";
/**
* 提现记录ID
*/
private String rid;
/**
* 应用ID
*/
private String appId;
/**
* 商户号
*/
private String mchNo;
/**
* 商户名称
*/
private String mchName;
/**
* 服务商号
*/
private String isvNo;
/**
* 支付接口代码
*/
private String ifCode;
/**
* 渠道子商户号
*/
private String channelSubMchId;
/**
* 支付订单号
*/
private String payOrderId;
/**
* 当前查询余额,单位分 (不准确,可能此时账户余额有变动)
*/
private Long currentBalance;
/**
* 申请提现金额,单位分
*/
private Long cashoutAmount;
/**
* 提现状态: 0-提现单创建, 1-提现中, 2-提现成功, 3-提现失败
*/
private Byte state;
/**
* 渠道提现单ID
*/
private String channelRid;
/**
* 失败原因
*/
private String failInfo;
/**
* 提现成功时间
*/
private Date successTime;
/**
* 提现银行名称
*/
private String bankName;
/**
* 提现账户
*/
private String bankAccount;
/**
* 提现账户名称
*/
private String bankAccountName;
/**
* 创建者用户ID
*/
private Long createdUid;
/**
* 创建人名称
*/
private String createdBy;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}

View File

@@ -0,0 +1,137 @@
package com.jeequan.jeepay.core.entity;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 对账批次表
* </p>
*
* @author [mybatis plus generator]
* @since 2022-09-09
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class CheckBatch extends BaseModel implements Serializable {
private static final long serialVersionUID=1L;
/**
* 对账批次号支付接口代码ifCode_渠道商户号_对账日期
*/
private String batchNo;
/**
* 支付接口代码
*/
private String ifCode;
/**
* 渠道商户号
*/
private String channelMchNo;
/**
* 对账日期
*/
private Date billDate;
/**
* 对账批次处理状态0-未处理,1-已处理
*/
private Byte state;
/**
* 所有差错总单数
*/
private Integer diffCount;
/**
* 待处理的差错总单数
*/
private Integer unHandleDiffCount;
/**
* 平台交易总单数
*/
private Integer totalCount;
/**
* 渠道交易总单数
*/
private Integer channelTotalCount;
/**
* 平台交易总金额
*/
private Long totalAmount;
/**
* 渠道交易总金额
*/
private Long channelTotalAmount;
/**
* 平台退款总单数
*/
private Integer totalRefundCount;
/**
* 渠道退款总单数
*/
private Integer channelTotalRefundCount;
/**
* 平台退款总金额
*/
private Long totalRefundAmount;
/**
* 渠道退款总金额
*/
private Long channelTotalRefundAmount;
/**
* 平台总手续费
*/
private Long totalFee;
/**
* 渠道总手续费
*/
private Long channelTotalFee;
/**
* 原始对账文件存放地址
*/
private String orgBillFilePath;
/**
* 下载/解析状态:0-失败,1-成功
*/
private Byte releaseState;
/**
* 下载/解析失败的描述信息
*/
private String releaseErrMsg;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}

View File

@@ -0,0 +1,136 @@
package com.jeequan.jeepay.core.entity;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.openapi.ParamException;
import lombok.Getter;
import lombok.Setter;
import org.springframework.util.Assert;
/**
* TODO
* 分账结算信息
* @author crystal
* @date 2024/5/15 13:58
*/
@Setter
@Getter
public class DivisionSettleInfo {
private String settleType;
/**
* 身份证人像面
*/
private String idCardFrontUrl;
/**
* 身份证国徽面
*/
private String idCardBackUrl;
/**
* 身份证名称
*/
private String idCardName;
/**
* 身份证号码
*/
private String idCardNo;
/**
* 身份证有效开始日期
*/
private String idCardStartDate;
/**
* 身份证有效结束日期
*/
private String idCardEndDate;
/**
* 是否长期 1是 0
*/
private Byte isLongTerm;
/**
* 结算卡卡号面
*/
private String bankCardFrontUrl;
/**
* 银行卡背面
*/
private String bankCardBackUrl;
/**
* 结算卡号
*/
private String bankCardNo;
/**
* 开户地区 省-市-区
*/
private String bankAreaName;
/**
* 开户地区CODE 省CODE-市CODE-区CODE
*/
private String bankAreaCode;
/**
* 开户银行
*/
private String bankName;
/**
* 开户支行联行号
*/
private String bankBranchNo;
/**
* 开户支行名称
*/
private String bankBranchName;
/**
* 银行卡预留手机号
*/
private String phone;
/**
* 校验参数
*/
public void preCheck(String settleType) {
Assert.notNull(this.getIdCardName(),"姓名不能空");
Assert.notNull(this.getIdCardFrontUrl(),"身份证头像面不能为空");
Assert.notNull(this.getIdCardBackUrl(),"身份证国徽面不能为空");
Assert.notNull(this.getIdCardNo(),"身份证号不能为空");
Assert.notNull(this.getIdCardStartDate(),"身份证有效期开始时间不能为空");
if(this.getIsLongTerm() == null || CS.NO == this.getIsLongTerm()){
Assert.notNull(this.getIdCardEndDate(),"身份证有效期截至时间不能为空");
}else{
this.setIdCardEndDate("长期");
}
if("BANK".equals(settleType)){
Assert.notNull(this.getBankCardNo(),"银行卡卡号不能为空");
Assert.notNull(this.getBankCardFrontUrl(),"银行卡卡号面不能为空");
Assert.notNull(this.getBankCardBackUrl(),"银行卡背面不能为空");
Assert.notNull(this.getBankAreaName(),"开户地区名称不能为空");
Assert.notNull(this.getBankAreaCode(),"开户地区编码不能为空");
Assert.notNull(this.getBankName(),"开户行名称不能为空");
Assert.notNull(this.getBankBranchNo(),"开户支行联行号不能为空");
Assert.notNull(this.getBankBranchName(),"开户支行名称不能为空");
}else if("ZFB".equals(settleType)){
Assert.notNull(this.getBankCardNo(),"支付宝登录账号不能为空");
}else{
throw new ParamException("暂不支持当前方式");
}
}
}

View File

@@ -0,0 +1,38 @@
package com.jeequan.jeepay.core.entity;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* TODO
*
* @author crystal
* @date 2024/5/17 11:19
*/
@Data
@NoArgsConstructor
public class DivisionSubjectEx{
private String divisionNo;
private String channelDivisionNo;
// 0-个人, 1-商户 (目前仅支持服务商appI获取个人openId, 即: PERSONAL_OPENID 不支持 PERSONAL_SUB_OPENID )
private Byte userType;
private String ifCode;
private DivisionSettleInfo channelExt;
private String remark;
public DivisionSubjectEx(String divisionNo,Byte userType, String ifCode, DivisionSettleInfo channelExt,String remark) {
this.divisionNo = divisionNo;
this.userType = userType;
this.ifCode = ifCode;
this.channelExt = channelExt;
this.remark = remark;
}
}

View File

@@ -0,0 +1,117 @@
package com.jeequan.jeepay.core.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 服务商信息表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Data
@Accessors(chain = true)
public class IsvInfo extends BaseModel implements Serializable {
private static final long serialVersionUID=1L;
/**
* 渠道持有者类型
* @see com.jeequan.jeepay.core.constants.CS.SYS_ROLE_TYPE
*/
private String ownerType;
/**
* 渠道持有者ID
* 若是代理这是代理编号;
* 若是商户则是商户编号;
*/
private String ownerNo;
/**
* 服务商号
*/
@TableId
private String isvNo;
/**
* 服务商名称
*/
private String isvName;
/**
* 1一级渠道
* 2二级渠道
*/
private Integer isvLevel;
/**
* 服务商简称
*/
private String isvShortName;
/**
* 联系人姓名
*/
private String contactName;
/**
* 联系人手机号
*/
private String contactTel;
/**
* 联系人邮箱
*/
private String contactEmail;
/**
* 状态: 0-停用, 1-正常
*/
private Byte state;
/**
* 备注
*/
private String remark;
/**
* 创建者用户ID
*/
private Long createdUid;
/**
* 创建者姓名
*/
private String createdBy;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
/**
* 自动绑定下级开关
*/
@TableField(exist = false)
private Byte configStatus;
/**
* 数据的用户类型
*/
@TableField(exist = false)
private String infoType;
}

View File

@@ -0,0 +1,35 @@
package com.jeequan.jeepay.core.entity;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
@Data
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class IsvUserConn extends BaseModel {
private String infoType;
private String infoId;
private String isvNo;
private String ifCode;
/**
* 渠道关联开关
*/
private Byte status;
/**
* 通道配置开关
*/
private Byte configStatus;
private String agentNo;
}

View File

@@ -0,0 +1,160 @@
package com.jeequan.jeepay.core.entity;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.model.BaseModel;
import com.jeequan.jeepay.core.model.Capability;
import com.jeequan.jeepay.core.model.MchExtInfo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
import java.util.List;
/**
* <p>
* 商户应用表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-06-15
*/
@Data
@Accessors(chain = true)
public class MchApp extends BaseModel {
public static final String SIGN_TYPE_MD5 = "MD5";
public static final String SIGN_TYPE_RSA2 = "RSA2";
private static final long serialVersionUID=1L;
/**
* 应用ID
*/
private String appId;
/**
* 应用名称
*/
private String appName;
/**
* 商户号
*/
private String mchNo;
/**
* 服务商号
*/
private String agentNo;
/**
* 顶级服务商号
*/
private String topAgentNo;
/**
* 是否默认: 0-否、 1-是api接口未显式指定应用则使用默认应用
*/
private Byte defaultFlag;
/**
* 应用状态: 0-停用, 1-正常
*/
private Byte state;
/**
* 轮询绑定状态。0 - 未开通1 - 已开通自动绑定2 - 不开通自动绑定
*/
private int pollingBindState;
/**
* 支持的加签方式: MD5、 RSA2若使用系统测试或者app必须支持MD5
*/
private String appSignType;
/**
* 应用公钥RSA2
*/
private String appRsa2PublicKey;
/**
* 应用私钥(MD5)
*/
private String appSecret;
/**
* 备注
*/
private String remark;
/**
* 创建者用户ID
*/
private Long createdUid;
/**
* 创建者姓名
*/
private String createdBy;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
/**
* 应用功能
*/
private List<Capability> capabilities;
/**
* 开通需求
*/
private List<Capability> preCapabilities;
/**
* 是否开通轮询
*/
private String turnsPay;
/**
* 0: 线下,
* 1: 线上
* 2: 专属
*/
private Integer range;
/**
* 是否支持API,
* 0: 不支持
* 1: 支持
*/
private Integer apiFlag;
/**
* 应用的功能code前端保存的时候传递该参数
*/
private List<String> capabilityCodeList;
/**
* 应用信息
*/
private List<MchExtInfo> information;
private String mccCode;
private List<JSONObject> qualificationList;
/**
* 预开通的方案
*/
private String predicOpenPackage;
/**
* 预开通的产品
*/
private String predicOpenProduct;
}

View File

@@ -0,0 +1,356 @@
package com.jeequan.jeepay.core.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
import java.util.function.Function;
/**
* <p>
* 特约商户进件信息表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-12-28
*/
@EqualsAndHashCode(callSuper = false)
@Data
@Accessors(chain = true)
public class MchApplyment extends BaseModel {
/**
* 状态:
* 0-未发起(草稿)、
* 1-审核中、
* 2-进件成功、
* 3-驳回待修改、
* 4-待验证、 5-待签约、6-签约完成/审核成功,等待其他操作、 7-等待系统预审核、 8-预审核拒绝 ,
* 11-图片待提交
*/
/** 未发起(草稿)*/
public static final byte STATE_SAVE = 0;
/** 审核中 */
public static final byte STATE_AUDITING = 1;
/** 进件成功 */
public static final byte STATE_SUCCESS = 2;
/** 驳回待修改,该状态下,提交审核不需要运营后台审核 */
public static final byte STATE_REJECT_WAIT_MODIFY = 3;
/** 待验证, 待补充资料等 */
public static final byte STATE_WAIT_VERIFY = 4;
/** 待签约 */
public static final byte STATE_WAIT_SIGN = 5;
/** 签约完成 */
public static final byte STATE_FINISH_SIGN = 6;
/** 预审,需要运营后台审核 */
public static final byte STATE_WAIT_PRE_AUDITING = 7;
/** 预审审核驳回,改状态下,再次发起审核时,需要运营后台审核 */
public static final byte STATE_WAIT_PRE_AUDIT_REJECT = 8;
/** 通过未生效,主要用于部分通道商户信息变更次日生效的情况 */
public static final byte STATE_SUCCESS_INEFFECTIVE = 9;
/** 待复审 */
public static final byte STATE_SUCCESS_NEED_SECOND_VERIFY = 12;
/** 任务等待中, 后根据提交的剩余步骤去执行相关的商户操作 */
public static final byte STATE_AUDITING_WAIT = 100;
/** 待商户确认 */
public static final byte STATE_AFFIRM = 30;
/** 通道人工审核 */
public static final byte STATE_UPSTREAM_MANUAL_REVIEW = 11;
/** 风控 */
public static final byte STATE_WAIT_RISK = 20;
/** 冻结 */
public static final byte STATE_WAIT_FREEZE = 21;
/** 注销 */
public static final byte STATE_WAIT_LOGOUT = 22;
/** 1-个人, 2-个体工商户, 3-企业, 4-党政、机关及事业单位, 5-其他组织, 6-个人卖家 **/
public static final byte MERCHANT_TYPE_PERSONAL = 1;
public static final byte MERCHANT_TYPE_INDIVIDUAL = 2;
public static final byte MERCHANT_TYPE_ENTERPRISE = 3;
public static final byte MERCHANT_TYPE_GOV = 4;
public static final byte MERCHANT_TYPE_OTHER = 5;
public static final byte MERCHANT_TYPE_PERSONAL_SELLER= 6; // 收付通新增个人卖家指无营业执照已持续从事电子商务经营活动满6个月且期间经营收入累计超过20万元的个人商家。
/** B-对公, C-对私 **/
public static final String SETT_ACCOUNT_TYPE_CORPORATE = "B";
public static final String SETT_ACCOUNT_TYPE_PERSONAL = "C";
/**
* 默认 收款商户
*/
public static final String REFUND_WAY_PAYMENT = "payment";
/**
* 平台户
*/
public static final String REFUND_WAY_PLATFORM = "platform";
private static final long serialVersionUID = 1L;
/**
* 回调链接
*/
private String notifyUrl;
/**
* 系统申请单号
*/
private String applyId;
private String subApplyId;
/**
* 渠道申请单号
*/
private String channelApplyNo;
/**
* 渠道要求的自定义商户号建议采用mchNo_时间戳10位的形式
*/
private String channelDiyMchNo;
/**
* 收单机构编号
*/
private String channelMchNo;
/**
* 商户号
*/
private String mchNo;
/**
* 渠道商号
*/
private String isvNo;
/**
* 服务商号
*/
private String agentNo;
/**
* 顶级服务商号
*/
private String topAgentNo;
/**
* 支付接口代码
*/
private String ifCode;
/**
* 接口名称
*/
private String ifName;
/**
* 商户全称
*/
private String mchFullName;
/**
* 商户简称
*/
private String mchShortName;
/**
* 商户类型: 1-个人, 2-个体工商户, 3-企业, 4-党政、机关及事业单位, 5-其他组织
*/
private Byte merchantType;
/**
* 联系人(不一定的法人)姓名
*/
private String contactName;
/**
* 联系人电话
*/
private String contactPhone;
/**
* 省市县编码 (非必填, 放在外层用作搜索方便)
*/
private String areaCode;
/**
* 省市县名称描述
*/
private String areaInfo;
/**
* 详细地址
*/
private String address;
/**
* 商户进件详细消息JSON类型
*/
private String applyDetailInfo;
/**
* 状态: 0-未发起(草稿)、 1-审核中、 2-进件成功、 3-驳回待修改、 4-待验证、 5-待签约、6-签约完成/审核成功,等待其他操作、 7-等待系统预审核、 8-预审核拒绝
*/
private Byte state;
/**
* 备注信息
*/
private String remark;
/**
* 运营端的备注信息
*/
private String mgrRemark;
/**
* 服务商端备注
*/
private String agtRemark;
/**
* 商户端备注
*/
private String mchRemark;
/**
* 入网操作剩余步骤,总共有几步主要看通道
*/
private Byte remainStep;
/**
* 进件成功接口返回参数, 用于配置到商户侧的参数信息
*/
private String succResParameter;
/**
* 渠道拓展参数1
*/
private String channelVar1;
/**
* 渠道拓展参数2
*/
private String channelVar2;
@TableField(exist = false)
private String wxCertState;
@TableField(exist = false)
private String aliCertState;
/**
* 门店入驻成功接口返回参数
*/
private String storeSuccResParameter;
/**
* 响应提示信息(一般进件异常或提示信息)
*/
private String applyErrorInfo;
/**
* 商户所属拓展员ID
*/
private Long epUserId;
/**
* 进件来源
*/
private String applyPageType;
/**
* 默认结算方式
* 部分通道可以根据传参发起多种结算方式的订单
*/
private String settlementType;
/**
* 自动配置的应用ID不为空自动进行关联等一系列配置
*/
private String autoConfigMchAppId;
/**
* 自动配置结果信息
*/
private String autoConfigResultInfo;
/**
* 创建者用户ID
*/
private Long createdUid;
/**
* 创建者姓名
*/
private String createdBy;
/**
* 最后一次请求上游时间
*/
private Date lastApplyAt;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
/**
* 支付配置参数ID关联t_mch_pay_interface_config的ID
*/
private Long payInterfaceId;
/**
* 进件时使用的入网配置参数
*/
private String ifParams;
/**
* 退款类型 payment:收款商户 platform 平台账户
*/
private String refundWay;
@TableField(exist = false)
private Integer wxAuthenticationState;
@TableField(exist = false)
private Integer zfbAuthenticationState;
/**
* 反扫权限开关。102未指定根据业务判断是否开关
* 为空同2
*/
private Integer scanPayPerm;
public boolean scanPayPermFlag(Function<Void, Boolean> function) {
if (scanPayPerm == 1) {
return true;
}
if (scanPayPerm == 0) {
return false;
}
if (function != null) {
return function.apply(null);
}
// 默认根据接结算方式判断
return !CS.SETTLEMENT_TYPE.D0.equals(settlementType);
}
}

View File

@@ -0,0 +1,136 @@
package com.jeequan.jeepay.core.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 商户分账接收者账号绑定关系表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-08-19
*/
@Data
@Accessors(chain = true)
public class MchDivisionReceiver extends BaseModel {
private static final long serialVersionUID=1L;
/**
* 分账接收者ID
*/
private Long receiverId;
/**
* 接收者账号别名
*/
private String receiverAlias;
/**
* 组ID便于商户接口使用
*/
private Long receiverGroupId;
/**
* 组名称
*/
private String receiverGroupName;
/**
* 商户号
*/
private String mchNo;
/**
* 服务商号
*/
private String isvNo;
/**
* 应用ID
*/
private String appId;
/**
* 支付接口代码
*/
private String ifCode;
/**
* 分账接收账号类型: 0-个人(对私) 1-商户(对公)
*/
private Byte accType;
/**
* 分账接收账号
*/
private String accNo;
/**
* 分账接收账号名称
*/
private String accName;
/**
* 渠道分账接收账号(账号创建完成后渠道侧账号)
*/
private String channelAccNo;
/**
* 分账关系类型(参考微信), 如: SERVICE_PROVIDER 服务商等
*/
private String relationType;
/**
* 当选择自定义时,需要录入该字段。 否则为对应的名称
*/
private String relationTypeName;
/**
* 分账比例
*/
private BigDecimal divisionProfit;
/**
* 分账状态(本系统状态,并不调用上游关联关系): 1-正常分账, 0-暂停分账
*/
private Byte state;
/**
* 上游绑定返回信息,一般用作查询绑定异常时的记录
*/
private String channelBindResult;
/**
* 渠道特殊信息(发起创建分账用户时渠道特殊参数,参考盛付通)
*/
private String channelExtInfo;
/**
* 绑定成功时间
*/
private Date bindSuccessTime;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
/**
* 绑定的应用名称
*/
@TableField(exist = false)
private String appName;
}

View File

@@ -0,0 +1,156 @@
package com.jeequan.jeepay.core.entity;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 商户信息表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Data
@Accessors(chain = true)
public class MchInfo extends BaseModel implements Serializable {
private static final long serialVersionUID=1L;
public static final byte TYPE_NORMAL = 1; //商户类型: 1-普通商户
public static final byte TYPE_ISVSUB = 2; //商户类型: 2-特约商户
public static final String REFUND_MODEL_PLAT = "plat"; // 支持的退款方式 平台
public static final String REFUND_MODEL_API = "api"; // 支持的退款方式 接口
public static final String MCH_LEVEL_M0 = "M0"; // 商户级别:简单
public static final String MCH_LEVEL_M1 = "M1"; // 商户级别:高级
public static final byte STATE_YES = 0; // 商户状态: 0-停用
public static final byte STATE_NO = 1; // 商户状态: 1-正常
public static final byte STATE_NO_MGR = 2; // 商户状态: 2-由运营平台停用
/**
* 商户号
*/
private String mchNo;
/**
* 商户名称
*/
private String mchName;
/**
* 商户简称
*/
private String mchShortName;
/**
* 类型: 1-普通商户, 2-特约商户(服务商模式)
*/
private Byte type;
/**
* 支持的退款方式 ["plat", "api"]
*/
@TableField(typeHandler = FastjsonTypeHandler.class)
private JSONArray refundMode;
/**
* 商户级别: M0(页面简洁,仅基础收款功能), M1(支持api调用 支持配置应用及分账、转账功能)
*/
private String mchLevel;
/**
* 服务商号
* @Deprecated 用户信息不再关联唯一渠道号
*/
private String isvNo;
/**
* 服务商号
*/
private String agentNo;
private String agentNoArr;
/**
* 顶级服务商号
*/
private String topAgentNo;
/**
* 联系人姓名
*/
private String contactName;
/**
* 联系人手机号
*/
private String contactTel;
/**
* 联系人邮箱
*/
private String contactEmail;
/**
* 商户状态: 0-停用, 1-正常2-由运营平台停用
*/
private Byte state;
/**
* 商户备注
*/
private String remark;
/**
* 初始用户ID创建商户时允许商户登录的用户
*/
private Long initUserId;
/**
* 登录用户名
*/
private String loginUsername;
/**
* 支付密码(敏感信息密码Sensitive information password)
*/
private String sipw;
/**
* 广告开关 0-关闭 1-开启
*/
private Byte advertFlag;
/**
* 创建者用户ID
*/
private Long createdUid;
/**
* 创建者姓名
*/
private String createdBy;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}

View File

@@ -0,0 +1,128 @@
package com.jeequan.jeepay.core.entity;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import java.util.Date;
/**
* <p>
* 特约商户进件信息表
* </p>
*
* @author [mybatis plus generator]
* @since 2023-12-05
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class MchModifyApplyment extends BaseModel {
private static final long serialVersionUID = 1L;
public static final byte MODIFY_TYPE_BASE = 1;
public static final byte MODIFY_TYPE_SETTLEMENT = 2;
public static final byte MODIFY_TYPE_RATE = 3;
public static final byte MODIFY_TYPE_SUPPLEMENTS = 4;
public static final byte MODIFY_TYPE_COMMON = 5;
public static final byte MODIFY_TYPE_SETTLEMENT_TYPE = 6;
/**
* 退货账户类型变更
*/
public static final byte MODIFY_TYPE_REFUND_ACCOUNT_TYPE = 7;
/**
* 商户变更系统申请单号
*/
private String modifyApplyId;
/**
* 系统申请单号/进件商户号
*/
private String applyId;
/**
* 渠道申请单号
*/
private String channelApplyNo;
/**
* 通道商户号,收单机构编号
*/
private String channelMchNo;
/**
* 商户号
*/
private String mchNo;
/**
* 支付接口代码, 字段冗余
*/
private String ifCode;
/**
* 接口名称, 字段冗余方便检索
*/
private String ifName;
/**
* 商户本次变更前的数据JSON类型
*/
private String originDetailInfo;
/**
* 商户变更详细信息JSON类型
*/
private String applyDetailInfo;
/**
* 上游接口返回参数
*/
private String channelVar1;
/**
* 1、基本资料变更; 2、结算信息变更; 3、费率信息变更; 4、身份信息补充; 5、通用变更(待定) 7:退货类型变更
*/
private Byte modifyApplyType;
/**
* 1: 本地变更; 2: 变更并同步到上游通道;该字段有值则说明该条数据是运营端或者服务商端代变更的数据
*/
private String otherOperationType;
public static final String OPERATION_TYPE_LOCAL = "1";
public static final String OPERATION_TYPE_SYNC = "2";
private Byte state;
private String remark;
private String remainStep;
private String applyErrorInfo;
private String applyPageType;
private Long createdUid;
private String createdBy;
private Date createdAt;
private Date updatedAt;
}

View File

@@ -0,0 +1,147 @@
package com.jeequan.jeepay.core.entity;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 商户门店表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-12-28
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName(value = "t_mch_store", autoResultMap = true)
public class MchStore extends BaseModel implements Serializable {
private static final long serialVersionUID=1L;
// 蚂蚁店铺创建状态(与支付宝一致): 0-未创建; 99-已完结; -1-失败; 031-已提交审核
public final static String ALIPAY_SHOP_STATUS_NOT_EXISTS = "0";
public final static String ALIPAY_SHOP_STATUS_SUCCESS = "99";
public final static String ALIPAY_SHOP_STATUS_FAIL = "-1";
public final static String ALIPAY_SHOP_STATUS_AUDITING = "031";
/**
* 门店ID
*/
@TableId(value = "store_id")
private String storeId;
/**
* 门店名称
*/
private String storeName;
/**
* 商户号
*/
private String mchNo;
/**
* 服务商号
*/
private String agentNo;
/**
* 顶级服务商号
*/
private String topAgentNo;
/**
* 绑定应用ID
*/
private String bindAppId;
/**
* 是否默认: 0-否、 1-是api接口未显式指定门店则使用默认门店下单
*/
private Byte defaultFlag;
/**
* 经度
*/
private String lng;
/**
* 纬度
*/
private String lat;
/**
* 门头照
*/
private String storeOuterImg;
/**
* 内景照
*/
private String storeInnerImg;
/**
* 门店Logo
*/
private String storeLogo;
/**
* 省市县编码 (非必填, 放在外层用作搜索方便)
*/
@TableField(typeHandler = FastjsonTypeHandler.class)
private JSONArray areaCode;
/**
* 联系人手机号
*/
private String contactPhone;
/**
* 所在地址
*/
private String address;
/**
* 蚂蚁店铺ID
*/
private String alipayShopId;
/**
* 蚂蚁店铺申请单ID
*/
private String alipayShopCreateId;
/**
* 蚂蚁店铺创建状态(与支付宝一致): 0-未创建; 99-已完结; -1-失败; 031-已提交审核
*/
private String alipayShopStatus;
/**
* 备注
*/
private String remark;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}

View File

@@ -0,0 +1,202 @@
package com.jeequan.jeepay.core.entity;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 商户门店设备配置表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-12-28
*/
@Data
@Accessors(chain = true)
public class MchStoreDevice extends BaseModel implements Serializable {
private static final long serialVersionUID=1L;
public static final byte DEVICE_TYPE_SPEAKER = 1; // 云喇叭
public static final byte DEVICE_TYPE_PRINTER = 2; // 打印机
public static final byte DEVICE_TYPE_POS = 3; // 扫码POS
public static final byte DEVICE_TYPE_AUTO_POS = 4; // 智能POS
public static final byte DEVICE_TYPE_PLUGIN = 5; // 收银插件
public static final byte DEVICE_TYPE_FACE_APP = 6; // 刷脸设备
public static final byte DEVICE_TYPE_RUYI = 7; // 如意Lite
// 绑定类型
public static final byte DEVICE_BIND_TYPE_STORE = 0; // 门店
public static final byte DEVICE_BIND_TYPE_QRC = 1; // 码牌
// 设备表类型 和 订单表类型转换关系
public static Object covertDeviceType(Object deviceType) {
if (deviceType instanceof Byte) {
switch ((Byte) deviceType) {
case DEVICE_TYPE_POS: return PayOrder.DEVICE_TYPE_SCAN_POS;
case DEVICE_TYPE_AUTO_POS: return PayOrder.DEVICE_TYPE_AUTO_POS;
case DEVICE_TYPE_PLUGIN: return PayOrder.DEVICE_TYPE_CASH_PLUGIN;
case DEVICE_TYPE_FACE_APP: return PayOrder.DEVICE_TYPE_FACE_APP;
case DEVICE_TYPE_RUYI: return PayOrder.DEVICE_TYPE_ALIPAY_RUYI_LITE;
}
}else {
switch ((String) deviceType) {
case PayOrder.DEVICE_TYPE_SCAN_POS: return DEVICE_TYPE_POS;
case PayOrder.DEVICE_TYPE_AUTO_POS: return DEVICE_TYPE_AUTO_POS;
case PayOrder.DEVICE_TYPE_CASH_PLUGIN: return DEVICE_TYPE_PLUGIN;
case PayOrder.DEVICE_TYPE_FACE_APP: return DEVICE_TYPE_FACE_APP;
case PayOrder.DEVICE_TYPE_ALIPAY_RUYI_LITE: return DEVICE_TYPE_RUYI;
}
}
return null;
}
// 支付宝如意设备型号
public static final Map<String, String> ALIPAY_IOT_DEVICE_MAP = new HashMap<>();
static {
ALIPAY_IOT_DEVICE_MAP.put("alipayRuYi", "201901111100635561");
ALIPAY_IOT_DEVICE_MAP.put("alipayRuYiPro", "202109071403204809");
ALIPAY_IOT_DEVICE_MAP.put("alipayRuYi2", "202008061702346558");
}
/**
* 设备ID
*/
private Long deviceId;
/**
* 设备名称
*/
private String deviceName;
/**
* 批次号
*/
private String batchId;
/**
* 关联厂商配置ID
*/
private Long configId;
/**
* 设备类型: 1-云喇叭, 2-云打印
*/
private Byte deviceType;
/**
* 设备厂商:参考配置表
*/
private String provider;
/**
* 设备号
*/
private String deviceNo;
/**
* 设备参数json字符串
*/
private String deviceParams;
/**
* 业务配置参数json字符串
*/
private String bizConfigParams;
/**
* 绑定码牌ID批量添加云喇叭设备时绑定的码牌ID与云喇叭设备一对一关系
*/
private Long bindQrcId;
/**
* 门店ID
*/
private String storeId;
/**
* 商户号
*/
private String mchNo;
/**
* 应用appId
*/
private String appId;
/**
* 服务商号
*/
private String agentNo;
/**
* 状态: 0-停用1-启用
*/
private Byte state;
/**
* 商户绑定状态: 0-未绑定1-已绑定
*/
private Byte bindState;
/**
* 绑定类型: 0-门店1-码牌
*/
private Byte bindType;
/**
* 绑定时间
*/
private Date bindTime;
/**
* 解绑时间
*/
private Date unbindTime;
/**
* 蚂蚁店铺Iot设备绑定状态 0-未绑定1-已绑定
*/
private Byte alipayBindState;
/**
* 蚂蚁店铺ID
*/
private String alipayShopId;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
@TableField(typeHandler = FastjsonTypeHandler.class)
private JSONObject marqueeInfo;
/**
* 轮播图
*/
@TableField(typeHandler = FastjsonTypeHandler.class)
private List<JSONObject> carouselPicInfo;
/**
* 付款区域背景图
*/
@TableField(typeHandler = FastjsonTypeHandler.class)
private JSONObject payPicInfo;
}

View File

@@ -0,0 +1,127 @@
package com.jeequan.jeepay.core.entity;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* <p>
* 商户辅助终端信息报备表
* </p>
*
* @author [mybatis plus generator]
* @since 2022-04-26
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class MchStoreTerminal extends BaseModel {
private static final long serialVersionUID=1L;
/**
* 表ID
*/
private Long trmId;
/**
* 终端编号
*/
private String trmNo;
/**
* 终端名称
*/
private String trmName;
/**
* 设备类型 1-终端 2-扫码pos
*/
private Long trmType;
/**
* 商户号
*/
private String mchNo;
/**
* 商户名称
*/
private String mchName;
/**
* 门店ID
*/
private String storeId;
/**
* 门店名称
*/
private String storeName;
/**
* 应用ID
*/
private String appId;
/**
* 服务商号
*/
private String agentNo;
/**
* 区域编码
*/
private String areacode;
/**
* 区域编码名称
*/
private String areacodeNames;
/**
* 布放位置
*/
private String detailAddress;
/**
* 经度
*/
private String lng;
/**
* 纬度
*/
private String lat;
/**
* 状态: 0-停用 1-启用
*/
private Byte state;
/**
* 渠道绑定管理 { ifCode:{ ifCode:"", ifCodeName: "", state: 1, errInfo: ""} }
*/
private JSONObject channelBindInfo;
/**
* 是否默认 1-是, 0-否
*/
private Byte defaultFlag;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}

View File

@@ -0,0 +1,89 @@
package com.jeequan.jeepay.core.entity;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
@EqualsAndHashCode(callSuper = false)
@Data
@Accessors(chain = true)
public class MchSubInfo extends BaseModel {
/**
* 商户号(原进件申请单号)
*/
private String mchApplyId;
/**
* 渠道商户号
*/
private String channelMchNo;
/**
* 渠道号
*/
private String channelId;
/**
* 渠道子商户号
*/
private String subMchId;
/**
* 渠道类型
* WX
* ZFB
*/
private String subMchType;
/**
* 渠道来源,银联网联等
*/
private String subMchWay;
/**
* 子商户备注信息
*/
private String remark;
/**
* 子商户状态
*/
private String status;
/**
* 是否主要使用1是
* 若是主要使用,则将该记录的认证状态作为商户的实名认证状态
*/
private Integer mainUse;
/**
* 子商户认证状态
*/
private Integer authStatus;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
/** 未实名 */
public static final Integer AUTH_STATUS_UNAUTHORIZED = 0;
/** 认证状态未知 */
public static final Integer AUTH_STATUS_UNKNOWN = -1;
/** 已注销 */
public static final Integer AUTH_STATUS_LOGOFF = -2;
/** 已实名 */
public static final Integer AUTH_STATUS_AUTHORIZED = 1;
}

View File

@@ -0,0 +1,46 @@
package com.jeequan.jeepay.core.entity;
import lombok.Data;
import java.util.Date;
@Data
public class MchVideoAuth {
private Long id;
/**
* 商户号
*/
private String mchNo;
/**
* 任务号
*/
private String taskId;
/**
* 视频号用户ID
*/
private String userId;
private String uniqueId;
/**
* 视频号用户昵称
*/
private String name;
/**
* 存储额外字段json格式
*/
private String extra;
/**
* 最后一次授权时间
*/
private Date lastAuthTime;
private Date createTime;
}

View File

@@ -0,0 +1,45 @@
package com.jeequan.jeepay.core.entity;
import lombok.Data;
import java.util.Date;
@Data
public class MchVideoCache {
private Long id;
/**
* 商户号
*/
private String mchNo;
/**
* 任务号
*/
private String taskId;
/**
* 视频号用户ID
*/
private String userId;
private String uniqueId;
/**
* 视频号用户昵称
*/
private String name;
/**
* 存储额外字段json格式
*/
private String extra;
private String objectId;
private String exportId;
private Date createTime;
}

View File

@@ -0,0 +1,74 @@
package com.jeequan.jeepay.core.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 商户公众号消息接收用户列表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-12-28
*/
@Data
@Accessors(chain = true)
public class MchWxmpUser implements Serializable {
private static final long serialVersionUID=1L;
public static final byte SEND_STATE_CLOSE = 0;
public static final byte SEND_STATE_OPEN = 1;
public static final byte SEND_STATE_ERROR = 2;
/**
* 用户编号
*/
private Long userId;
/**
* 系统用户ID
*/
private Long sysUserId;
/**
* 微信昵称
*/
private String nickname;
/**
* 微信openId
*/
private String wxOpenId;
/**
* 微信 appId
*/
private String wxAppId;
/**
* 商户号
*/
private String mchNo;
/**
* 消息推送状态0-未开启1-开启 2推送失败已自动关闭
*/
private Byte sendStatus;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}

View File

@@ -0,0 +1,416 @@
package com.jeequan.jeepay.core.entity;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 支付订单表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Data
@Accessors(chain = true)
public class PayOrder extends BaseModel implements Serializable {
private static final long serialVersionUID=1L;
public static final byte STATE_INIT = 0; //订单生成
public static final byte STATE_ING = 1; //支付中
public static final byte STATE_SUCCESS = 2; //支付成功
public static final byte STATE_FAIL = 3; //支付失败
public static final byte STATE_CANCEL = 4; //已撤销
public static final byte STATE_REFUND = 5; //已退款
public static final byte STATE_CLOSED = 6; //订单关闭
public static final byte REFUND_STATE_NONE = 0; //未发生实际退款
public static final byte REFUND_STATE_SUB = 1; //部分退款
public static final byte REFUND_STATE_ALL = 2; //全额退款
public static final byte DIVISION_MODE_FORBID = 0; //该笔订单不允许分账
public static final byte DIVISION_MODE_AUTO = 1; //支付成功按配置自动完成分账
public static final byte DIVISION_MODE_MANUAL = 2; //商户手动分账(解冻商户金额)
public static final byte DIVISION_STATE_UNHAPPEN = 0; //未发生分账
public static final byte DIVISION_STATE_WAIT_TASK = 1; //等待分账任务处理
public static final byte DIVISION_STATE_ING = 2; //分账处理中
public static final byte DIVISION_STATE_FINISH = 3; //分账任务已结束(不体现状态)
// 设备类型
public static final String DEVICE_TYPE_QR_CODE = "qr_code"; // 码牌
public static final String DEVICE_TYPE_SCAN_POS = "scan_pos"; // 扫码POS
public static final String DEVICE_TYPE_AUTO_POS = "auto_pos"; // 智能POS
public static final String DEVICE_TYPE_CASH_PLUGIN = "cash_plugin"; // 收银插件
public static final String DEVICE_TYPE_FACE_APP = "face_app"; // 刷脸设备
public static final String DEVICE_TYPE_ALIPAY_RUYI_LITE = "ruyi_lite"; // 如意Lite
/**
* 支付订单号
*/
private String payOrderId;
/**
* 扩展商户号 现在的申请单编号 改版后的商户号
*/
private String mchExtNo;
/**
* 用户号 原先的商户号
*/
private String mchNo;
/**
* 服务商号
*/
private String isvNo;
/**
* 服务商号
*/
private String agentNo;
/**
* 顶级服务商号
*/
private String topAgentNo;
/**
* 应用ID
*/
private String appId;
/**
* 商户名称
*/
private String mchName;
/**
* 类型: 1-普通商户, 2-特约商户(服务商模式)
*/
private Byte mchType;
/**
* 商户门店ID
*/
private String storeId;
/**
* 门店名称
*/
private String storeName;
/**
* 经度
*/
private String lng;
/**
* 纬度
*/
private String lat;
/**
* 所在地址
*/
private String address;
/**
* 设备类型qr_code-码牌scan_pos-扫码POSauto_pos-智能POS
*/
private String deviceType;
/**
* 设备号
*/
private String deviceNo;
/**
* 设备厂商
*/
private String deviceProvider;
/**
* 码牌ID
*/
private Long qrcId;
/**
* 商户订单号
*/
private String mchOrderNo;
/**
* 支付接口代码
*/
private String ifCode;
/**
* 支付方式代码
*/
private String wayCode;
/**
* 支付方式代码分类
*/
private String wayCodeType;
/**
* 支付金额,单位分
*/
private Long amount;
/**
* 商户手续费费率快照
*/
private String mchFeeRate;
/**
* 商户实际手续费,单位分 ( 订单手续费 - 手续费退还金额 )
*/
private Long mchFeeAmount;
/**
* 商户收单手续费,单位分 (订单快照)
*/
private Long mchOrderFeeAmount;
/**
* 三位货币代码,人民币:cny
*/
private String currency;
/**
* 支付状态: 0-订单生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭
*/
private Byte state;
/**
* 向下游回调状态, 0-未发送, 1-已发送
*/
private Byte notifyState;
/**
* 客户端IP
*/
private String clientIp;
/**
* 商品标题
*/
private String subject;
/**
* 商品描述信息
*/
private String body;
/**
* 渠道服务商机构号
*/
private String channelIsvNo;
/**
* 渠道子商户号
*/
private String channelMchNo;
/**
* 特定渠道发起额外参数
*/
private String channelExtra;
/**
* 渠道用户标识,如微信openId,支付宝账号
*/
private String channelUser;
/**
* 渠道订单号
*/
private String channelOrderNo;
/**
* 支付凭证上交易单号(微信、支付宝等交易单号)
*/
private String platformOrderNo;
/**
* 支付凭证上商户单号(微信、支付宝等商户单号)
*/
private String platformMchOrderNo;
/**
* 渠道特殊业务数据,各渠道业务自处理数据
*/
private String channelBizData;
/**
* 退款状态: 0-未发生实际退款, 1-部分退款, 2-全额退款
*/
private Byte refundState;
/**
* 退款次数
*/
private Integer refundTimes;
/**
* 退款总金额,单位分
*/
private Long refundAmount;
/**
* 订单分账模式0-该笔订单不允许分账, 1-支付成功按配置自动完成分账, 2-商户手动分账(解冻商户金额)
*/
private Byte divisionMode;
/**
* 订单分账状态0-未发生分账, 1-等待分账任务处理, 2-分账处理中, 3-分账任务已结束(不体现状态)
*/
private Byte divisionState;
/**
* 最新分账时间
*/
private Date divisionLastTime;
/**
* 渠道支付错误码
*/
private String errCode;
/**
* 渠道支付错误描述
*/
private String errMsg;
/**
* 商户扩展参数
*/
private String extParam;
/**
* 异步通知地址
*/
private String notifyUrl;
/**
* 页面跳转地址
*/
private String returnUrl;
/**
* 买家备注
*/
private String buyerRemark;
/**
* 卖家备注
*/
private String sellerRemark;
/**
* 商户拓展员ID
*/
private Long epUserId;
/**
* 门店收银员ID
*/
private Long storeUserId;
/**
* 会员ID
*/
private String mbrId;
/**
* 会员手机号
*/
private String mbrTel;
/**
* 订单失效时间
*/
private Date expiredTime;
/**
* 订单支付成功时间
*/
private Date successTime;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
/**
* 交易卡类型 00借记卡 01贷记卡 02零钱/余额 03花呗 04数字货币 99其他
*/
private String drType;
/**
* 结算类型 D0 D1 T1 DS 定时结算
*/
private String settleType;
/**
* 优惠金额
*/
private Long discountAmt;
/**
* 优惠折扣
*/
private BigDecimal discountScale;
/**
* 实付金额
*/
private Long findAmt;
/**
* 扩展分账金额
*/
private Long extDivAmt;
/**
* 营销活动补贴金额
*/
private Long marketAmt;
/**
* 提现费率
*/
private BigDecimal cashRate;
/**
* 提现费率
*/
private Long cashFee;
/**
* 支付原始数据
*/
private String payData;
private String routeId;
}

View File

@@ -0,0 +1,204 @@
package com.jeequan.jeepay.core.entity;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.Date;
/**
* TODO
* 订单统计
* @author crystal
* @date 2024/3/14 16:24
*/
@Data
@Accessors(chain = true)
public class PayOrderCount extends BaseModel {
/**
* 总金额
*/
private Long totalAmt;
/**
* 总笔数
*/
private Long totalNum;
/**
* 交易手续费
*/
private Long totalFeeAmt;
/**
* 成功交易金额
*/
private Long totalSuccAmt;
/**
* 成功交易笔数
*/
private Long totalSuccNum;
/**
* 失败交易金额
*/
private Long totalFailAmt;
/**
* 失败交易笔数
*/
private Long totalFailNum;
/**
* 入账金额
*/
private Long totalEntryAmt;
/**
* 实付金额
*/
private Long totalFinalAmt;
/**
* 优惠金额
*/
private Long totalDiscountAmt;
/**
* 补贴金额
*/
private Long totalMarketAmt;
/**
* 垫资手续费
*/
private Long totalCashFee;
/**
* 退款金额
*/
private Long totalRefundAmt;
/**
* 退款手续费
*/
private Long totalRefundFeeAmt;
/**
* 退款笔数
*/
private Long totalRefundNum;
/**
* 扩展分账金额
*/
private Long totalExtDivAmt;
/**
* 成功率
*/
private BigDecimal succRate;
private String applyId;
private String mchFullName;
private String mchShortName;
private Date createdAt;
private String groupDate;
/**
* 用户号
*/
private String mchNo;
/**
* 用户名
*/
private String mchName;
private String agentNo;
private String agentName;
private String storeId;
private String storeName;
private String wayCode;
private Long agentProfit;
private String deviceType;
private String deviceNo;
private String deviceName;
private String provider;
private String isvNo;
private String isvName;
private String ifCode;
private String ifName;
private String wayType;
// private String typeName;
private Byte qrcType;
private Long calBaseAmount;
private Long calProfitAmount;
private Long calFeeAmount;
private String name;
private Long totalWxSuccAmt;
private Long totalZfbSuccAmt;
private Long totalWxSuccNum;
private Long totalZfbSuccNum;
private Long totalWxAmt;
private Long totalWxNum;
private Long totalZfbAmt;
private Long totalZfbNum;
private String routeId;
/**
* 微信成功率
*/
private BigDecimal wxRate;
/**
* 支付宝成功率
*/
private BigDecimal zfbRate;
}

View File

@@ -0,0 +1,197 @@
package com.jeequan.jeepay.core.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 分账记录表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-08-19
*/
@Data
@Accessors(chain = true)
public class PayOrderDivisionRecord extends BaseModel {
public static final byte STATE_WAIT = 0; // 待分账
public static final byte STATE_SUCCESS = 1; // 分账成功(明确成功)
public static final byte STATE_FAIL = 2; // 分账失败(明确失败)
public static final byte STATE_ING = 3; // 分账处理中(一般为渠道侧或定时任务)
public static final byte STATE_ACCEPT = 4; // 分账已受理(上游受理)
private static final long serialVersionUID=1L;
/**
* 分账记录ID
*/
private Long recordId;
/**
* 商户号
*/
private String mchNo;
/**
* 服务商号
*/
private String isvNo;
/**
* 应用ID
*/
private String appId;
/**
* 商户名称
*/
private String mchName;
/**
* 类型: 1-普通商户, 2-特约商户(服务商模式)
*/
private Byte mchType;
/**
* 支付接口代码
*/
private String ifCode;
/**
* 系统支付订单号
*/
private String payOrderId;
/**
* 支付订单渠道支付订单号
*/
private String payOrderChannelOrderNo;
/**
* 订单金额,单位分
*/
private Long payOrderAmount;
/**
* 订单实际分账金额, 单位:分(订单金额 - 商户手续费 - 已退款金额) , 是否减去手续费取决对商户的配置
*/
private Long payOrderDivisionAmount;
/**
* 计算分账金额的分账基数规则(退分使用) ORDER_AMOUNT-订单金额, INCOME_AMOUNT-入账金额(订单金额-手续费)
*/
private String calBaseAmountType;
/**
* 系统分账批次号
*/
private String batchOrderId;
/**
* 上游分账批次号
*/
private String channelBatchOrderId;
/**
* 状态: 0-待分账 1-分账成功, 2-分账失败
*/
private Byte state;
/**
* 上游返回数据包
*/
private String channelRespResult;
/**
* 账号快照》 分账接收者ID
*/
private String receiverId;
/**
* 账号快照》 分账任务ID
*/
private String taskId;
/**
* 账号快照》 分账接收者别名
*/
private String receiverAlias;
/**
* 账号快照》 分账接收账号类型: 0-个人 1-商户
*/
private Byte accType;
/**
* 账号快照》 分账接收账号
*/
private String accNo;
/**
* 账号快照》 分账接收账号名称
*/
private String accName;
/**
* 渠道分账接收账号(账号创建完成后渠道侧账号)
*/
private String channelAccNo;
/**
* 账号快照》 分账关系类型(参考微信), 如: SERVICE_PROVIDER 服务商等
*/
private String relationType;
/**
* 账号快照》 当选择自定义时,需要录入该字段。 否则为对应的名称
*/
private String relationTypeName;
/**
* 账号快照》 配置的实际分账比例
*/
private BigDecimal divisionProfit;
/**
* 计算该接收方的分账金额,单位分
*/
private Long calDivisionAmount;
/**
* 退款次数
*/
private Integer refundTimes;
/**
* 退款总金额,单位分
*/
private Long refundAmount;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
/**
* 商户号
*/
private String mchExtNo;
private String remark;
@TableField(exist = false)
private String ifName;
}

View File

@@ -0,0 +1,189 @@
package com.jeequan.jeepay.core.entity;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 分账记录表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-08-19
*/
@Data
@Accessors(chain = true)
public class PayOrderDivisionRefundRecord extends BaseModel {
public static final byte STATE_WAIT = 0; // 退款处理中
public static final byte STATE_SUCCESS = 1; // 退款成功
public static final byte STATE_FAIL = 2; // 退款失败
private static final long serialVersionUID=1L;
/**
* 分账退款订单号(支付系统生成订单号)
*/
private String divisionRefundId;
/**
* 商户号
*/
private String mchNo;
/**
* 服务商号
*/
private String isvNo;
/**
* 应用ID
*/
private String appId;
/**
* 商户名称
*/
private String mchName;
/**
* 类型: 1-普通商户, 2-特约商户(服务商模式)
*/
private Byte mchType;
/**
* 支付接口代码
*/
private String ifCode;
/**
* 状态: 0-退款中 1-退款成功 2-退款失败
*/
private Byte state;
/**
* 系统支付订单号
*/
private String payOrderId;
/**
* 支付订单渠道订单号
*/
private String payOrderChannelOrderNo;
/**
* 订单支付金额
*/
private Long payOrderAmount;
/**
* 支付订单退款订单号
*/
private String payOrderRefundOrderId;
/**
* 支付订单退款发生金额, 单位:分
*/
private Long payOrderRefundAmount;
/**
* 分账记录ID
*/
private Long divisionRecordId;
/**
* 系统分账批次号
*/
private String divisionBatchOrderId;
/**
* 账号快照》 分账接收者ID
*/
private String receiverId;
/**
* 账号快照》 分账任务ID便于商户接口使用
*/
private String taskId;
/**
* 接收者账号别名
*/
private String receiverAlias;
/**
* 账号快照》 分账接收账号类型: 0-个人 1-商户
*/
private Byte accType;
/**
* 账号快照》 分账接收账号
*/
private String accNo;
/**
* 账号快照》 分账接收账号名称
*/
private String accName;
/**
* 账号快照》 渠道分账接收账号(账号创建完成后渠道侧账号)
*/
private String channelAccNo;
/**
* 账号快照》 分账关系类型(参考微信), 如: SERVICE_PROVIDER 服务商等
*/
private String relationType;
/**
* 账号快照》 当选择自定义时,需要录入该字段。 否则为对应的名称
*/
private String relationTypeName;
/**
* 分账金额,单位分
*/
private Long divisionAmount;
/**
* 账号快照》 配置的实际分账比例
*/
private BigDecimal divisionProfit;
/**
* 分账退款金额,单位分
*/
private Long divisionRefundAmount;
/**
* 渠道订单号
*/
private String channelOrderNo;
/**
* 渠道错误码
*/
private String errCode;
/**
* 渠道错误描述
*/
private String errMsg;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}

View File

@@ -0,0 +1,227 @@
package com.jeequan.jeepay.core.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* <p>
* 退款订单表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Data
@Accessors(chain = true)
public class RefundOrder extends BaseModel {
public static final byte STATE_INIT = 0; //订单生成
public static final byte STATE_ING = 1; //退款中
public static final byte STATE_SUCCESS = 2; //退款成功
public static final byte STATE_FAIL = 3; //退款失败
public static final byte STATE_CLOSED = 4; //退款任务关闭
public static final byte PART_REFUND_TYPE = 2;
public static final byte ALL_REFUND_TYPE = 1;
/**
* 默认退款方式
*/
public static final String REFUND_ACCOUNT_DEFAULT = "1";
/**
* 一般户退款模式
*/
public static final String REFUND_ACCOUNT_PLAT = "2";
private static final long serialVersionUID=1L;
/**
* 退款订单号(支付系统生成订单号)
*/
private String refundOrderId;
/**
* 支付订单号与t_pay_order对应
*/
private String payOrderId;
/**
* 渠道支付单号与t_pay_order channel_order_no对应
*/
private String channelPayOrderNo;
/**
* 商户号
*/
private String mchNo;
/**
* 服务商号
*/
private String isvNo;
/**
* 服务商号
*/
private String agentNo;
/**
* 顶级服务商号
*/
private String topAgentNo;
/**
* 商户门店ID
*/
private String storeId;
/**
* 门店名称
*/
private String storeName;
/**
* 应用ID
*/
private String appId;
/**
* 商户名称
*/
private String mchName;
/**
* 类型: 1-普通商户, 2-特约商户(服务商模式)
*/
private Byte mchType;
/**
* 商户退款单号(商户系统的订单号)
*/
private String mchRefundNo;
/**
* 支付方式代码
*/
private String wayCode;
/**
* 支付接口代码
*/
private String ifCode;
/**
* 支付金额,单位分
*/
private Long payAmount;
/**
* 退款金额,单位分
*/
private Long refundAmount;
/**
* 手续费退还金额, 单位:分
*/
private Long refundFeeAmount;
/**
* 三位货币代码,人民币:cny
*/
private String currency;
/**
* 退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败,4-退款任务关闭
*/
private Byte state;
/**
* 客户端IP
*/
private String clientIp;
/**
* 退款原因
*/
private String refundReason;
/**
* 渠道订单号
*/
private String channelOrderNo;
/**
* 渠道特殊业务数据,各渠道业务自处理数据
*/
private String channelBizData;
/**
* 渠道错误码
*/
private String errCode;
/**
* 渠道错误描述
*/
private String errMsg;
/**
* 特定渠道发起时额外参数
*/
private String channelExtra;
/**
* 通知地址
*/
private String notifyUrl;
/**
* 扩展参数
*/
private String extParam;
/**
* 门店收银员ID
*/
private Long storeUserId;
/**
* 订单退款成功时间
*/
private Date successTime;
/**
* 退款失效时间(失效后系统更改为退款任务关闭状态)
*/
private Date expiredTime;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
/**
* 所属通道名称
*/
@TableField(exist = false)
private String ifName;
/**
* 商户号
*/
private String mchExtNo;
}

View File

@@ -0,0 +1,140 @@
package com.jeequan.jeepay.core.entity;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* <p>
* 系统用户表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-23
*/
@Data
@Accessors(chain = true)
public class SysUser extends BaseModel {
private static final long serialVersionUID=1L;
public static final byte UEST_TYPE_ADMIN = 1;
public static final byte UEST_TYPE_NORMAL = 2;
public static final byte UEST_TYPE_EXPAND = 3;
public static final byte UEST_TYPE_DIRECTOR = 11;
public static final byte UEST_TYPE_CASHIER = 12;
/**
* 系统用户ID
*/
private Long sysUserId;
/**
* 登录用户名
*/
private String loginUsername;
/**
* 真实姓名
*/
private String realname;
/**
* 手机号
*/
private String telphone;
/**
* 性别 0-未知, 1-男, 2-女
*/
private Byte sex;
/**
* 头像地址
*/
private String avatarUrl;
/**
* 员工编号
*/
private String userNo;
/**
* 邀请码
*/
private String inviteCode;
/**
* 用户类型: 1-超级管理员 2-普通用户 3-拓展员
*/
private Byte userType;
/**
* 团队ID
*/
private Long teamId;
/**
* 是否队长 1-是 0-否
*/
private Byte isTeamLeader;
/**
* 状态 0-停用 1-启用
*/
private Byte state;
/**
* 所属系统: MGR-运营平台, MCH-商户中心
*/
private String sysType;
/**
* 所属商户ID / 0(平台)
*/
private String belongInfoId;
/**
* MFA绑定状态 0-未绑定 1-已绑定
*/
private Byte mfaBindState;
/**
* MFA验证秘钥
*/
private String mfaSecretKey;
/**
* 预留信息(最多十个字)
*/
private String safeWord;
/**
* 密码过期时间
*/
private Date pwdExpiredTime;
/**
* 最后一次重置密码时间
*/
private Date lastResetPwdTime;
/**
* 上次登录时间
*/
private Date lastLoginTime;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}

View File

@@ -0,0 +1,255 @@
package com.jeequan.jeepay.core.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 转账订单表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-08-11
*/
@Data
@Accessors(chain = true)
public class TransferOrder extends BaseModel {
/**
* 内扣
*/
public static final String COST_TYPE_ORDER = "ORDER";
/**
* 外扣
*/
public static final String COST_TYPE_ACCOUNT = "ACCOUNT";
/** 代发 */
public static final Integer TRANSFER_TYPE_OUT = 0;
/** 充值 */
public static final Integer TRANSFER_TYPE_IN = 1;
/**
* 订单类型0代发1充值
*/
public static final Integer TRANSFER_TYPE_DF = 0; //转账失败
public static final Integer TRANSFER_TYPE_CZ = 1; //转账关闭
/** 入账方式 **/
public static final String ENTRY_WX_CASH = "WX";
public static final String ENTRY_ALIPAY_CASH = "ZFB";
public static final String ENTRY_BANK_CARD = "BANK";
public static final byte STATE_INIT = 0; //订单生成
/** 转账中, 已发起代付, 等待三方处理结果 */
public static final byte STATE_ING = 1;
public static final byte STATE_SUCCESS = 2; //转账成功
public static final byte STATE_FAIL = 3; //转账失败
public static final byte STATE_CLOSED = 4; //转账关闭
private static final long serialVersionUID=1L;
/**
* 转账订单号
*/
private String transferId;
/**
* 商户号
*/
private String mchNo;
/**
* 服务商号
*/
private String isvNo;
/**
* 服务商号
*/
private String agentNo;
/**
* 应用ID
*/
private String appId;
/**
* 商户名称
*/
private String mchName;
/**
* 类型: 1-普通商户, 2-特约商户(服务商模式)
*/
private Byte mchType;
/**
* 商户订单号
*/
private String mchOrderNo;
/**
* 支付接口代码
*/
private String ifCode;
/**
* 商户转账手续费费率快照, 空表示没有配置费率信息,但是不影响转账。 无非就是统计数据不准确+服务商无法计算分润。
*/
private String mchFeeRate;
/**
* 手续费扣费方式
* ORDER - 内扣,即从订单金额中扣除
* ACCOUNT - 外扣,从手续费账户中扣除
*/
private String feeCostType;
/**
* 商户转账手续费,单位分 (订单快照)
*/
private Long mchOrderFeeAmount;
/**
* 入账方式: WX-微信零钱; ZFB-支付宝转账; BANK-银行卡
*/
private String entryType;
/**
* 转账金额,单位分
*/
private Long amount;
/**
* 三位货币代码,人民币:cny
*/
private String currency;
/**
* 转账发起方账户号码
*/
private String originAccountNo;
/**
* 转账发起方账户名称
*/
private String originAccountName;
/**
* 收款账号
*/
private String accountNo;
/**
* 收款人姓名
*/
private String accountName;
/**
* 收款人开户行名称
*/
private String bankName;
/**
* 转账备注信息
*/
private String transferDesc;
/**
* 客户端IP
*/
private String clientIp;
/**
* 支付状态: 0-订单生成, 1-转账中, 2-转账成功, 3-转账失败, 4-订单关闭
*/
private Byte state;
/**
* 特定渠道发起额外参数
*/
private String channelExtra;
/**
* 渠道订单号
*/
private String channelOrderNo;
/**
* 渠道支付错误码
*/
private String errCode;
/**
* 渠道支付错误描述
*/
private String errMsg;
/**
* 商户扩展参数
*/
private String extParam;
/**
* 异步通知地址
*/
private String notifyUrl;
/**
* 转账成功时间
*/
private Date successTime;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
/**
* 关联流水号
*/
private String flowNo;
/**
* 转账发起对象id
*/
private String transferSubjectIdFq;
private Integer walletId;
/**
* 转账接收对象id
*/
private String transferSubjectIdJs;
/**
* 新版商户号也就是申请单id
*/
private String mchExtNo;
private String batchId;
private Integer transferType;
@TableField(exist = false)
private BigDecimal transAmount;
private String accountType;
/**
* 实到金额, 单位分
*/
private Long realAmount;
}

View File

@@ -0,0 +1,268 @@
package com.jeequan.jeepay.core.entity;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 转账对象表
* </p>
*
* @author [mybatis plus generator]
* @since 2024-04-25
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class TransferSubject extends BaseModel implements Serializable {
/**
* 不可用
*/
public static final byte STATE_DISABLE = 0;
/**
* 启用
*/
public static final byte STATE_ENABLE = 1;
/**
* 初次审核
*/
public static final byte STATE_REVIEW = 2;
/**
* 关闭后二次启用待审核
*/
public static final byte STATE_ENABLE_REVIEW = 3;
// 0已签约1审核中2未签约3:已解约4:解约中;5:暂存;6:暂停 ;7未知
public static final byte SIGN_STATE_SUCCESS = 0;
public static final byte SIGN_STATE_AUDITING = 1;
public static final byte SIGN_STATE_SIGNING = 2;
public static final byte SIGN_STATE_LOGOUT = 3;
public static final byte SIGN_STATE_LOGOUT_AUDITING = 4;
public static final byte SIGN_STATE_ON_HOLD = 5;
public static final byte SIGN_STATE_ON_PAUSE = 6;
public static final byte SIGN_STATE_UNKNOWN = 7;
private static final long serialVersionUID = 1L;
/**
* 转账接收方
*/
public static final String SUBJECT_TYPE_RECEIVER = "JS";
/**
* 转账发起方
*/
public static final String SUBJECT_TYPE_SPONSOR = "FQ";
/**
* 即可以作为接收方,也可以作为发起方
*/
public static final String SUBJECT_TYPE_ALL = "ALL";
/**
* ID
*/
private String id;
/**
* 下游回调链接
*/
private String notifyUrl;
/**
* 下游申请单号
*/
private String transSubApplyId;
/**
* 转账主体申请单号
*/
private String transApplyId;
/**
* 渠道申请单号
*/
private String transChannelApplyNo;
/**
* 渠道签约ID
*/
private String transChannelSignNo;
/**
* 通道主体编号
*/
private String transChannelMchNo;
/**
* 主体类型.FQ: 发起方; JS: 接收方; ALL: 可发起, 可接收
*/
private String subjectType;
/**
* 应用ID
*/
private String appId;
/**
* 产品开通记录ID即packageOrder的ID
*/
private String openOrderId;
/**
* 商户号
*/
private String mchNo;
/**
* 服务商号
*/
private String isvNo;
/**
* 代理商号
*/
private String agentNo;
/**
* 顶级代理商号
*/
private String topAgentNo;
/**
* 转账接口代码
*/
private String transIfCode;
/**
* 主体名称
*/
private String subjectName;
/**
* 转账接口实例ID
*/
private Integer transInterfaceId;
/**
* 商户进件号,部分通道需要关联商户
*/
private String mchApplyId;
/**
* 关联的支付接口代码
*/
private String payIfCode;
/**
* 商户进件详细消息JSON类型
*/
private String applyDetailInfo;
/**
* 响应提示信息(一般进件异常或提示信息)
*/
private String applyErrorInfo;
/**
* 状态: 0-停用, 1-启用
*/
private Byte state;
/**
* 签约状态 0已签约1审核中2未签约3:已解约4:解约中;5:暂存;6:暂停 ;7未知
*/
private Integer signState;
/**
* 佣金结算周期(仅服务商配置, 用于代理商的佣金提现周期)
*/
private Integer settHoldDay;
/**
* 进件成功接口返回参数, 用于配置到商户侧的参数信息
*/
private String succResParameter;
/**
* 渠道拓展参数1
*/
private String channelVar1;
/**
* 渠道拓展参数2
*/
private String channelVar2;
/**
* 账户
*/
private String account;
/**
* 账户名称
*/
private String accountName;
/**
* 账户类型 B: 对公企业C对私个人
*/
private String accountType;
/**
* 账户信息 json
*/
private String accountMessage;
/**
* 联系人姓名
*/
private String realName;
/**
* 联系电话
*/
private String contactTel;
/**
* 备注
*/
private String remark;
/**
* 创建者用户ID
*/
private Long createdUid;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新者用户ID
*/
private Long updatedUid;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 最后一次请求上游时间
*/
private Date lastApplyAt;
private String entryType;
}

View File

@@ -0,0 +1,215 @@
package com.jeequan.jeepay.core.entity;
import lombok.Data;
import java.util.Date;
/**
* TODO
*
* @author deng
* @since 2024/5/13
*/
@Data
public class TransferWallet {
/**
* ID
*/
private Integer id;
private String transSubjectId;
/**
* 转账主体申请单号
*/
private String transApplyId;
/**
* 钱包申请单号, 部分通道一次签约可创建多个钱包
*/
private String walletApplyId;
/**
* 通道主体编号, 钱包编号等
*/
private String transChannelMchNo;
/**
* 主体名称, 钱包名称
*/
private String subjectName;
/**
* 手续费扣费方式
* @see com.jeequan.jeepay.core.entity.TransferOrder#COST_TYPE_ACCOUNT
* @see com.jeequan.jeepay.core.entity.TransferOrder#COST_TYPE_ORDER
*/
private String feeCostType;
/**
* 应用ID
*/
private String appId;
/**
* 商户号
*/
private String mchNo;
/**
* 渠道商号
*/
private String isvNo;
/**
* 转账接口代码
*/
private String transIfCode;
/**
* 记账本余额
*/
private Long accountBookBalance;
/**
* 每日下发额度
*/
private Long accountLimitBalance;
/**
* 记账的外卡状态,1:正常2其它
*/
private Integer cardStatus;
/**
* 代付钱包账户信息
*/
private String extCardInfo;
/**
* 记账本开通返回的完整参数
*/
private String extResponse;
/**
* 备注
*/
private String remark;
/**
* 最后一次交易时间
*/
private Date lastTransTime;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* (总)到支付宝月限额(分)
*/
private Long zfbMonthMax;
/**
* (总)到支付宝日限额(分)
*/
private Long zfbDayMax;
/**
* (总)个人支付宝单笔限额(分)
*/
private Long zfbPriOnceMax;
/**
* (总)企业支付宝单笔限额(分)
*/
private Long zfbCorOnceMax;
/**
* (总)到微信月限额(分)
*/
private Long wxMonthMax;
/**
* (总)到微信日限额(分)
*/
private Long wxDayMax;
/**
* (总)个人微信单笔限额(分)
*/
private Long wxPriOnceMax;
/**
* (总)企业微信单笔限额(分)
*/
private Long wxCorOnceMax;
/**
* (总)到银行卡月限额(分)
*/
private Long bankCardMonthMax;
/**
* (总)到银行卡日限额(分)
*/
private Long bankCardDayMax;
/**
* (总)到对私银行卡单笔限额(分)
*/
private Long bankCardPriOnceMax;
/**
* (总)到对公银行卡单笔限额(分)
*/
private Long bankCardCorOnceMax;
/**
* (剩)到支付宝月限额(分)
*/
private Long zfbMonthLast;
/**
* (剩)到支付宝日限额(分)
*/
private Long zfbDayLast;
/**
* (剩)到微信月限额(分)
*/
private Long wxMonthLast;
/**
* (剩)到微信日限额(分)
*/
private Long wxDayLst;
/**
* (剩)到银行卡月限额(分)
*/
private Long bankCardMonthLast;
/**
* (剩)到银行卡日限额(分)
*/
private Long bankCardDayLast;
public void initFromSubject(TransferSubject transferSubject) {
setTransSubjectId(transferSubject.getId());
setTransApplyId(transferSubject.getTransApplyId());
setTransIfCode(transferSubject.getTransIfCode());
setIsvNo(transferSubject.getIsvNo());
setAppId(transferSubject.getAppId());
setMchNo(transferSubject.getMchNo());
setSubjectName(transferSubject.getSubjectName());
}
}

View File

@@ -0,0 +1,40 @@
package com.jeequan.jeepay.core.exception;
import com.jeequan.jeepay.core.model.openapi.AccessError;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 一般异常信息的异常,全局捕获会抛出异常信息给前端
* @author Djh
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class AccessMsgException extends RuntimeException {
private final Serializable obj;
private final String code;
public AccessMsgException(AccessError error) {
this(error.getCode(),error.getMsg(),null);
}
public AccessMsgException(String code, String msg) {
this(code,msg,null);
}
public AccessMsgException(String code, String msg, Serializable obj) {
super(msg);
this.code = code;
this.obj = obj;
}
}

View File

@@ -0,0 +1,35 @@
package com.jeequan.jeepay.core.exception;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.model.ApiRes;
import lombok.Getter;
/*
* 自定义业务异常
*
* @author terrfly
*
* @date 2021/6/8 16:33
*/
@Getter
public class BizException extends RuntimeException{
private static final long serialVersionUID = 1L;
private ApiRes apiRes;
/** 业务自定义异常 **/
public BizException(String msg) {
super(msg);
this.apiRes = ApiRes.customFail(msg);
}
public BizException(ApiCodeEnum apiCodeEnum, String... params) {
super();
apiRes = ApiRes.fail(apiCodeEnum, params);
}
public BizException(ApiRes apiRes) {
super(apiRes.getMsg());
this.apiRes = apiRes;
}
}

View File

@@ -0,0 +1,77 @@
package com.jeequan.jeepay.core.exception;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.model.ApiRes;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.DataAccessException;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
* 异常信息自定义返回数据
*
* @author terrfly
*
* @date 2021/6/8 16:30
*/
@Configuration
public class BizExceptionResolver implements HandlerExceptionResolver {
private final Logger logger = LogManager.getLogger(BizExceptionResolver.class);
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
// 是否包含ss框架
boolean hasSpringSecurity = false;
try {
hasSpringSecurity = Class.forName("org.springframework.security.access.AccessDeniedException") != null;
} catch (Exception e) {
}
String outPutJson;
//业务异常
if(ex instanceof BizException) {
logger.error("公共捕捉[Biz]异常:{}",ex.getMessage());
outPutJson = ((BizException) ex).getApiRes().toJSONString();
}else if(ex instanceof DataAccessException || ex instanceof PersistenceException){
logger.error("公共捕捉[DataAccessException]异常:",ex);
outPutJson = ApiRes.fail(ApiCodeEnum.DB_ERROR).toJSONString();
}else if(hasSpringSecurity && ex instanceof org.springframework.security.access.AccessDeniedException) {
logger.error("公共捕捉[AccessDeniedException]异常:", ex);
outPutJson = ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR, ex.getMessage()).toJSONString();
}else{
logger.error("公共捕捉[Exception]异常:",ex);
outPutJson = ApiRes.fail(ApiCodeEnum.SYSTEM_ERROR, ex.getMessage()).toJSONString();
}
try {
this.outPutJson(response, outPutJson);
} catch (IOException e) {
logger.error("输出错误信息异常:", e);
}
return new ModelAndView();
}
public void outPutJson(HttpServletResponse res, String jsonStr) throws IOException {
res.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
res.getWriter().write(jsonStr);
res.getWriter().flush();
res.getWriter().close();
}
}

View File

@@ -0,0 +1,36 @@
package com.jeequan.jeepay.core.exception;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import lombok.Getter;
/*
* 请求渠道侧异常 exception
* 抛出此异常: 仅支持: 未知状态(需查单) 和 系统内异常
*
* @author terrfly
*
* @date 2021/6/8 17:28
*/
@Getter
public class ChannelException extends RuntimeException{
private static final long serialVersionUID = 1L;
private ChannelRetMsg channelRetMsg;
/** 业务自定义异常 **/
public ChannelException(ChannelRetMsg channelRetMsg) {
super(channelRetMsg != null ? channelRetMsg.getChannelErrMsg() : null);
this.channelRetMsg = channelRetMsg;
}
/** 未知状态 **/
public static ChannelException unknown(String channelErrMsg){
return new ChannelException(ChannelRetMsg.unknown(channelErrMsg));
}
/** 系统内异常 **/
public static ChannelException sysError(String channelErrMsg){
return new ChannelException(ChannelRetMsg.sysError(channelErrMsg));
}
}

View File

@@ -0,0 +1,33 @@
package com.jeequan.jeepay.core.exception;
import lombok.Getter;
import lombok.experimental.Accessors;
/**
* 数据校验异常
*
* @author deng
* @since 2024/5/17
*/
@Getter
@Accessors(chain = true, fluent = true)
public class DataCheckException extends RuntimeException{
private static final long serialVersionUID = 1L;
/**
* 校验前若发生过数据保存或变更,则需要回滚
*/
private final boolean needRollback;
/** 数据校验异常 **/
public DataCheckException(String msg, boolean needRollback) {
super(msg);
this.needRollback = needRollback;
}
/** 数据校验异常 **/
public DataCheckException(String msg) {
this(msg, false);
}
}

View File

@@ -0,0 +1,39 @@
package com.jeequan.jeepay.core.exception;
import lombok.Getter;
import lombok.Setter;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
/*
* Spring Security 框架自定义异常类
*
* @author terrfly
*
* @date 2021/6/15 11:23
*/
@Getter
@Setter
public class JeepayAuthenticationException extends InternalAuthenticationServiceException {
private BizException bizException;
public JeepayAuthenticationException(String msg, Throwable cause) {
super(msg, cause);
}
public JeepayAuthenticationException(String msg) {
super(msg);
}
public static JeepayAuthenticationException build(String msg){
return build(new BizException(msg));
}
public static JeepayAuthenticationException build(BizException ex){
JeepayAuthenticationException result = new JeepayAuthenticationException(ex.getMessage());
result.setBizException(ex);
return result;
}
}

View File

@@ -0,0 +1,47 @@
package com.jeequan.jeepay.core.exception;
import lombok.Getter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
/*
* 响应异常, 一般用于支付接口回调函数
*
* @author terrfly
*
* @date 2021/6/8 16:31
*/
@Getter
public class ResponseException extends RuntimeException{
private static final long serialVersionUID = 1L;
private ResponseEntity responseEntity;
/** 业务自定义异常 **/
public ResponseException(ResponseEntity resp) {
super();
this.responseEntity = resp;
}
/** 生成文本类型的响应 **/
public static ResponseException buildText(String text){
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.TEXT_HTML);
ResponseEntity entity = new ResponseEntity(text, httpHeaders, HttpStatus.OK);
return new ResponseException(entity);
}
/** 生成文本类型 状态码为500 的响应 **/
public static ResponseException buildText4HttpStatus500(String text){
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.TEXT_HTML);
ResponseEntity entity = new ResponseEntity(text, httpHeaders, HttpStatus.INTERNAL_SERVER_ERROR);
return new ResponseException(entity);
}
}

View File

@@ -0,0 +1,16 @@
package com.jeequan.jeepay.core.exception.openapi;
import com.jeequan.jeepay.core.exception.AccessMsgException;
import com.jeequan.jeepay.core.model.openapi.AccessError;
public class ParamException extends AccessMsgException {
public ParamException(String message) {
super(AccessError.CODE_ILLEGAL_PARAM_ERROR,message);
}
public ParamException(AccessError error) {
super(error);
}
}

View File

@@ -0,0 +1,107 @@
package com.jeequan.jeepay.core.interceptor;
import com.alibaba.fastjson.JSON;
import com.jeequan.jeepay.core.beans.RequestKitBean;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Component
public class ReqInfoInterceptor implements HandlerInterceptor {
@Autowired
private RequestKitBean requestKitBean;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, @NonNull Object handler) throws Exception {
// 所有请求第一个进入的方法
long startTime = System.currentTimeMillis();
httpServletRequest.setAttribute("startTime", startTime);
String contentType = httpServletRequest.getHeader(HttpHeaders.CONTENT_TYPE);
Enumeration<String> headerNames = httpServletRequest.getHeaderNames();
Map<String, Object> headers = new HashMap<>();
while (headerNames.hasMoreElements()) {
String key = headerNames.nextElement();
String value = httpServletRequest.getHeader(key);
headers.put(key, value);
}
if (handler instanceof HandlerMethod) {
val h = ((HandlerMethod) handler);
StringBuilder sb = new StringBuilder(1000);
sb.append("------------------------------------------------------------\n");
String typeName = h.getBean().getClass().getTypeName();
typeName = typeName.replaceAll("(\\w)\\w*\\.", "$1.");
int end = typeName.indexOf("$");
if (end == -1) {
end = typeName.length();
}
//部分请求链接
sb.append("URI : ").append(httpServletRequest.getRequestURI()).append("\n");
//Controller 的包名
sb.append("Controller : ").append(typeName, 0, end).append("\n");
//方法名称
sb.append("Method : ").append(h.getMethod().getName()).append("\n");
// 请求头
sb.append("headers : ").append(JSON.toJSONString(headers)).append("\n");
sb.append("Content-Type : ").append(contentType).append("\n");
// 所有的请求参数, 表单或json
sb.append("Params : ").append(requestKitBean.getReqParamJSON()).append("\n");
// body不在此处打印
log.info("request info : \n {}", sb);
}
return true;
}
@Override
public void postHandle(@NonNull HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, @NonNull Object o, ModelAndView modelAndView) {
}
@Override
public void afterCompletion(@NonNull HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, @NonNull Object o, Exception e) {
}
private Map<String, Object> getParameterInfo(HttpServletRequest request) {
Map<String, Object> parameter = new HashMap<>();
Map<String, String[]> parameterMap = request.getParameterMap();
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
String key = entry.getKey();
String[] parameterValues = entry.getValue();
if (parameterValues.length == 1) {
int length = parameterValues[0].length();
if (length > 255) {
parameter.put(key, parameterValues[0].substring(0, 255) + "...");
} else {
parameter.put(key, parameterValues[0]);
}
} else {
parameter.put(key, Arrays.toString(parameterValues));
}
}
return parameter;
}
}

View File

@@ -0,0 +1,21 @@
package com.jeequan.jeepay.core.interfaces;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.entity.PayOrderDivisionRefundRecord;
import com.jeequan.jeepay.core.entity.RefundOrder;
import java.util.List;
/***
* 业务订单查询接口
*
* @author terrfly
*
* @date 2023/10/23 11:03
*/
public interface IBizOrderQueryService {
/** 查询支付订单退款时: 分账明细信息(不入库) **/
List<PayOrderDivisionRefundRecord> queryPayOrderRefundDivisionRefundRecordList(RefundOrder refundOrder, PayOrder payOrder);
}

View File

@@ -0,0 +1,9 @@
package com.jeequan.jeepay.core.interfaces;
/** 当前项目类型管理 **/
public interface ICodeSysTypeManager {
/** 获取当前项目名称(全大写形式) **/
String getCodeSysName();
}

View File

@@ -0,0 +1,54 @@
package com.jeequan.jeepay.core.interfaces;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.entity.MchApplyment;
import com.jeequan.jeepay.core.entity.TransferSubject;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.oauth2.Oauth2Params;
import com.jeequan.jeepay.core.model.params.IsvParams;
import com.jeequan.jeepay.core.model.params.IsvsubMchParams;
import com.jeequan.jeepay.core.model.params.NormalMchParams;
/**
* 接口: 配置信息查询服务 (兼容 缓存 和 直接查询方式)
*
* @author terrfly
*
* @since 2021/11/18 14:41
*/
public interface IConfigContextQueryService {
MchApp queryMchApp(String mchNo, String mchAppId);
MchAppConfigContext queryMchInfoAndAppInfo(String mchAppId);
MchAppConfigContext queryMchInfoAndAppInfo(String mchNo, String mchAppId);
NormalMchParams queryNormalMchParams(String mchNo, String mchAppId, String ifCode);
IsvsubMchParams queryIsvsubMchParams(String mchNo, String mchAppId, String ifCode);
IsvsubMchParams queryNewIsvsubMchParams(String mchExtNo);
IsvParams queryIsvParams(String isvNo, String ifCode);
IsvParams queryTransferIsvParams(String isvNo, String ifCode);
IsvParams queryTransferIsvParams(TransferSubject transferSubject);
<T extends IsvParams> T queryIsvParams(MchApplyment mchApplyment);
Oauth2Params queryIsvOauth2Params(String isvNo, String ifCode);
Oauth2Params queryNormalOauth2Params(String mchNo, String mchAppId, String ifCode);
<T> T queryOauth2Params(String infoType, String infoId, String ifCode, Class<T> cls);
/**
* 新版获取接口
*
* @param mchNo 商户号
* @return
*/
MchAppConfigContext queryMchInfoAndAppInfoV2(String mchNo, String mchAppId, String applyId);
}

View File

@@ -0,0 +1,22 @@
package com.jeequan.jeepay.core.interfaces;
/*
* 商户/服务商 配置信息上下文服务
*
* @author terrfly
*
* @date 2021/6/8 17:41
*/
public interface IConfigContextService {
/** 初始化 [商户配置信息] **/
void initMchInfoConfigContext(String mchNo);
/** [商户应用支付参数配置信息] **/
void initMchAppConfigContext(String mchNo, String appId);
/** [ISV支付参数配置信息] **/
void initIsvConfigContext(String isvNo);
}

View File

@@ -0,0 +1,22 @@
package com.jeequan.jeepay.core.interfaces;
import com.jeequan.jeepay.core.model.OCRImgParams;
/**
* OCR api调用
*
* @author xiaoyu
*
* @date 2022/1/11 15:23
*/
public interface IOCRApiService {
/** 识别身份证信息接口 **/
OCRImgParams getIdCardInfo(String imgUrl);
/** 识别营业执照信息接口 **/
OCRImgParams getBusinessLicenceInfo(String imgUrl);
/** 识别银行卡信息接口 **/
OCRImgParams getBankCardInfo(String imgUrl);
}

View File

@@ -0,0 +1,26 @@
package com.jeequan.jeepay.core.interfaces.bill;
import com.jeequan.jeepay.core.entity.CheckBatch;
import java.util.Date;
/**
* 对账接口
*
* @author zx
*
* @date 2022/10/16 11:31
*/
public interface IReconciliationService {
/** 对账 **/
void queryChannelBillAndCheck(String ifCode, Date billDate);
/** 根据对账批次 重新发起批次对账 **/
void reloadBill4Batch(CheckBatch coreCheckBatch, String reloadType);
/** 处理差异 **/
void processCheckDiffBills(Date billDate);
}

View File

@@ -0,0 +1,31 @@
package com.jeequan.jeepay.core.interfaces.cashout;
import com.jeequan.jeepay.core.entity.ChannelAccountCashoutRecord;
import com.jeequan.jeepay.core.model.cashout.CashoutRetMsg;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import org.apache.commons.lang3.tuple.MutablePair;
import javax.servlet.http.HttpServletRequest;
/*
* 渠道提现通知解析实现
*
* @author zx
*
* @date 2021/5/8 15:14
*/
public interface IChannelCashoutNoticeService {
/** 获取到接口code **/
String getIfCode();
/** 解析参数: 提现rid 和 请求参数
* 异常需要自行捕捉并返回null , 表示已响应数据。
* **/
MutablePair<String, Object> parseParams(HttpServletRequest request, String rid);
/** 返回需要更新的提现状态 和响应数据 **/
CashoutRetMsg doNotice(HttpServletRequest request,
Object params, ChannelAccountCashoutRecord cashoutRecord, MchAppConfigContext mchAppConfigContext);
}

View File

@@ -0,0 +1,43 @@
package com.jeequan.jeepay.core.interfaces.device;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device;
/**
* 调起播报接口
*
* @author zx
*
* @date 2021/12/16 11:31
*/
public interface IPrinterService {
/** 调起打印
* @param deviceParams
* @param printPayOrderInfo
* **/
void send(JSONObject deviceParams, PayOrderInfo4Device printPayOrderInfo) throws BizException;
/** 打印机 自定义语音播报
* @param deviceParams
* @param printPayOrderInfo
* **/
void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device printPayOrderInfo) throws BizException;
/** 添加打印机
* @param deviceParams
* **/
String addPrinter(JSONObject deviceParams);
/** 修改打印机
* @param deviceParams
* **/
String editPrinter(JSONObject deviceParams);
/** 清除打印队列
* @param deviceParams
* **/
String clearPrinter(JSONObject deviceParams);
}

View File

@@ -0,0 +1,52 @@
package com.jeequan.jeepay.core.interfaces.device;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device;
/**
* 调起播报接口
*
* @author zx
*
* @date 2021/12/16 11:31
*/
public interface ISpeakerService {
/** 调起播报 **/
void send(JSONObject deviceParams, PayOrderInfo4Device speakPayOrderInfo) throws BizException;
/** 自定义语音播报 **/
void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device speakPayOrderInfo) throws BizException;
/**
* 绑定消息推送
*
* @param deviceParams
* @param isVersion
* @return
*/
default void bindSend(JSONObject deviceParams, boolean isVersion) {
}
/**
* 设备绑定查询接口
*
* @param deviceParams
* @return
*/
default JSONObject bindQuery(JSONObject deviceParams) {
return null;
}
/**
* 获取url
* @param reqData
* @return
*/
default JSONObject getUrl(JSONObject reqData){
return null;
}
}

View File

@@ -0,0 +1,17 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.entity.MchApplyment;
/**
* 进件 非通用业务接口聚合
*
* @author zx
*
* @date 2023/6/9 9:26
*/
public interface IApplymentApiService {
MchApplyment entry(String method, MchApplyment mchApplyment, JSONObject params);
}

View File

@@ -0,0 +1,28 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.core.model.params.IsvParams;
import java.util.List;
/*
* @Description: 获取mcc、银行编码、省市编码等
* @author zx
* @date 2021/5/2 15:10
*/
public interface IApplymentResourceService {
/** 获取mcc **/
String getMcc();
/** 获取银行编码 **/
IPage<JSONObject> getBankCode(IPage<JSONObject> iPage, JSONObject queryParams);
/** 获取省市编码 **/
List<JSONObject> getAreaCode(IsvParams isvParams, JSONObject reqParams);
/** type 自定义业务种类 获取商户号和json数据对象进行特定操作 **/
String sendPubRequst(String type, String mchNo, String applyId, String jsonStr);
}

View File

@@ -0,0 +1,24 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.model.bill.ChannelBillRQ;
import com.jeequan.jeepay.core.model.bill.ChannelBillRS;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import java.util.Date;
/*
* 调起上游渠道侧 获取对账单接口
*
* @author zx
*
* @date 2021/5/8 15:13
*/
public interface IBillDownloadService {
/** 获取到接口code **/
String getIfCode();
/** 查询 对账单 **/
ChannelBillRS convertStandardBill(ChannelBillRQ channelBillRQ, MchAppConfigContext mchAppConfigContext, Date billDate, String ifCode);
}

View File

@@ -0,0 +1,29 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import cn.hutool.core.lang.Pair;
import com.jeequan.jeepay.core.entity.ChannelAccountCashoutRecord;
import com.jeequan.jeepay.core.model.cashout.CashoutRetMsg;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
/**
* 渠道账号操作service
*
* @author terrfly
*
* @date 2022/11/09 08:59
*/
public interface IChannelAccountService {
/** 获取到接口code **/
String getIfCode();
/** 查询分账账户余额 **/
Pair<String, Long> queryBalanceAmount(MchAppConfigContext mchAppConfigContext, String ifCode);
/** 账户提现 **/
CashoutRetMsg cashout(ChannelAccountCashoutRecord cashoutRecord, MchAppConfigContext mchAppConfigContext, String ifCode);
/** 账户提现查询 **/
CashoutRetMsg cashoutQuery(ChannelAccountCashoutRecord cashoutRecord, MchAppConfigContext mchAppConfigContext, String ifCode);
}

View File

@@ -0,0 +1,44 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.http.ResponseEntity;
import javax.servlet.http.HttpServletRequest;
/*
* 渠道侧的支付订单通知解析实现 【分为同步跳转doReturn和异步回调(doNotify) 】
*
* @author terrfly
*
* @date 2021/5/8 15:14
*/
public interface IChannelNoticeService {
/** 通知类型 **/
enum NoticeTypeEnum {
DO_RETURN, //同步跳转
DO_NOTIFY //异步回调
}
/** 获取到接口code **/
String getIfCode();
/** 解析参数: 订单号 和 请求参数
* 异常需要自行捕捉并返回null , 表示已响应数据。
* **/
MutablePair<String, Object> parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum);
/** 返回需要更新的订单状态 和响应数据 **/
ChannelRetMsg doNotice(HttpServletRequest request,
Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum);
/** 数据库订单 状态更新异常 (仅异步通知使用) **/
ResponseEntity doNotifyOrderStateUpdateFail(HttpServletRequest request);
/** 数据库订单数据不存在 (仅异步通知使用) **/
ResponseEntity doNotifyOrderNotExists(HttpServletRequest request);
}

View File

@@ -0,0 +1,33 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.model.autopos.ChannelOrderAcceptParams;
import com.jeequan.jeepay.core.model.autopos.ChannelOrderAcceptRetMsg;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.params.IsvParams;
import javax.servlet.http.HttpServletRequest;
/*
* 渠道侧的订单通知解析实现 【支付通知payNotice和退款通知(refundNotice) 】
*
* @author zx
*
* @date 2021/5/8 15:14
*/
public interface IChannelOrderAcceptService {
/** 获取到接口code **/
String getIfCode();
/** 解析参数:
* 异常需要自行捕捉并返回null , 表示已响应数据。
* **/
ChannelOrderAcceptParams parseParams(HttpServletRequest request, IsvParams isvParams);
/** 返回需要插入的支付订单金额 和响应数据 **/
ChannelOrderAcceptRetMsg payNotice(HttpServletRequest request, Object params, MchAppConfigContext mchAppConfigContext, String ifCode) throws Exception;
/** 返回需要插入的退款订单金额 和响应数据 **/
ChannelOrderAcceptRetMsg refundNotice(HttpServletRequest request, Object params, MchAppConfigContext mchAppConfigContext, String ifCode);
}

View File

@@ -0,0 +1,43 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.RefundOrder;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.http.ResponseEntity;
import javax.servlet.http.HttpServletRequest;
/*
* 渠道侧的退款订单通知解析实现 【分为同步跳转doReturn和异步回调(doNotify) 】
*
* @author jmdhappy
*
* @date 2021/9/25 23:14
*/
public interface IChannelRefundNoticeService {
/** 通知类型 **/
enum NoticeTypeEnum {
DO_NOTIFY //异步回调
}
/** 获取到接口code **/
String getIfCode();
/** 解析参数: 订单号 和 请求参数
* 异常需要自行捕捉并返回null , 表示已响应数据。
* **/
MutablePair<String, Object> parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum);
/** 返回需要更新的订单状态 和响应数据 **/
ChannelRetMsg doNotice(HttpServletRequest request,
Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum);
/** 数据库订单 状态更新异常 (仅异步通知使用) **/
ResponseEntity doNotifyOrderStateUpdateFail(HttpServletRequest request);
/** 数据库订单数据不存在 (仅异步通知使用) **/
ResponseEntity doNotifyOrderNotExists(HttpServletRequest request);
}

View File

@@ -0,0 +1,23 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelUserInfoMsg;
/*
* @Description: 301方式获取渠道侧用户ID 如微信openId 支付宝的userId等
* @author terrfly
* @date 2021/5/2 15:10
*/
public interface IChannelUserService {
/** 获取到接口code **/
String getIfCode();
/** 获取重定向地址 **/
ChannelUserInfoMsg buildUserRedirectUrl(String callbackUrlEncode, MchAppConfigContext mchAppConfigContext);
/** 获取渠道用户ID pageType: 参考 QRCodeParams **/
String getChannelUserId(String pageType, JSONObject reqParams, MchAppConfigContext mchAppConfigContext, String ifCode);
}

View File

@@ -0,0 +1,26 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.entity.MchApplyment;
/**
* 斗拱 进件接口
*
* @author xiaoyu
*
* @date 2022/6/9 9:26
*/
public interface IDgApplymentApiService {
/** 分账配置 **/
MchApplyment dgpayConfigOpen(MchApplyment mchApplyment, JSONObject paramJSON);
/** 分账配置查询 **/
MchApplyment dgpayConfigOpenQuery(MchApplyment mchApplyment);
/** 微信参数配置 **/
MchApplyment wechatConfigSet(String isvNo, String mchNo, String appId, String jsapiPath, String feeType, String configWxBindLiteAppId, String configWxBindAppId, String bankChannelNo, String ifCode);
/** 微信实名认证 **/
MchApplyment wechatRealName(MchApplyment mchApplyment);
}

View File

@@ -0,0 +1,64 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.*;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.params.IsvParams;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import java.util.HashMap;
import java.util.List;
/**
* 分账接口
*
* @author terrfly
*
* @date 2021/8/22 08:59
*/
public interface IDivisionService {
/** 是否在支付订单退款业务完成后在发起退分业务
*
* 返回 false : 先退分 --》 再 退款主订单
* 返回 true: 先退款主订单, 并且明确退款成功后再退分。 退分模块: 1. 直接响应成功, 2.渠道特殊处理
* **/
boolean divisionRefundIsOrderRefundAfterProc();
/** 获取到接口code **/
String getIfCode();
/** 获取实际使用的接口code新增于克隆接口 **/
String getIfCode(MchDivisionReceiver mchDivisionReceiver);
/** 获取实际使用的接口code新增于克隆接口 **/
String getIfCode(PayOrder payOrder);
/** 获取实际使用的接口code新增于克隆接口 **/
String getIfCode(PayOrderDivisionRecord payOrderDivisionRecord);
/** 是否支持该分账 */
boolean isSupport();
/** 单次分账 (无需调用完结接口,或自动解冻商户资金) **/
ChannelRetMsg singleDivision(PayOrder payOrder, List<PayOrderDivisionRecord> recordList, MchAppConfigContext mchAppConfigContext);
/** 查询分账结果 **/
HashMap<Long, ChannelRetMsg> queryDivision(PayOrder payOrder, List<? extends PayOrderDivisionRecord> recordList, MchAppConfigContext mchAppConfigContext);
/** 分账退回 **/
ChannelRetMsg divisionRefund(PayOrderDivisionRecord payOrderDivisionRecord, PayOrderDivisionRefundRecord payOrderDivisionRefundRecord, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext);
/** 查询分账账户余额 **/
Long queryBalanceAmount(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext);
/** 账户提现 **/
ChannelRetMsg cashout(MchDivisionReceiver mchDivisionReceiver, Long amount, MchAppConfigContext mchAppConfigContext);
/** 分账完结 **/
String divisionFinishAfterDivision(PayOrderDivisionRecord divisionRecord, MchAppConfigContext mchAppConfigContext);
/** 新版绑定关系 **/
ChannelRetMsg bind(DivisionSubjectEx subjectEx, String isvNo);
}

View File

@@ -0,0 +1,28 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.MchApplyment;
/***
* 商户进件接口
*
* @author terrfly
*
* @date 2021/12/30 11:36
*/
public interface IFuiouApplymentApiService {
MchApplyment wechatConfigSet(MchApplyment mchApplyment, String jsapiPath, String subAppid, String subscribeAppid);
String wechatConfigGet(MchApplyment mchApplyment);
/** 电子协议生成接口 **/
MchApplyment elecContractGenerate(MchApplyment mchApplyment);
/** 电子协议签署接口 **/
MchApplyment elecContractSign(MchApplyment mchApplyment);
boolean uploadImg(MchApplyment mchApplyment);
MchApplyment attachConfirm(MchApplyment mchApplyment);
}

View File

@@ -0,0 +1,26 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.exception.BizException;
import java.util.ArrayList;
import java.util.List;
/***
* 获取进件数据
*
* @author zx
*
* @date 2022/01/17 09:52
*/
public interface IGetApplymentDataService {
/** 获取支行列表 */
default List<JSONObject> getBankBranchInfo(String isvNo, String bankAliasCode, String cityCode, String bankName, String branchName) throws BizException {
return new ArrayList<>();
}
default List<JSONObject> getBankBranchInfo(String isvNo, String bankAliasCode, String cityCode) throws BizException {
return new ArrayList<>();
}
}

View File

@@ -0,0 +1,18 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.MchApplyment;
import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo;
/***
* 特约商户 支付宝配置项
*
* @author terrfly
*
* @date 2022/08/18 09:52
*/
public interface IIsvmchAlipayConfigService {
/** 开户意愿查询 **/
ApplymentSignInfo alipayOpenSignInfo(MchApplyment mchApplyment);
}

View File

@@ -0,0 +1,37 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.MchApplyment;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.http.ResponseEntity;
import javax.servlet.http.HttpServletRequest;
/**
* 进件通知接口
*
* @author terrfly
*
* @date 2022/1/6 14:12
*/
public interface IIsvmchApplymentNotifyService {
/**
* 解析参数 返回申请单号和参数对象 (与业务无关)
* left 入网订单号
* right 入网回调参数
*/
MutablePair<String, Object> parseParams(HttpServletRequest request, String urlApplyId);
/**
* 返回需要更新的订单状态 和响应数据 (验签等操作)
* @param request
* @param params 解密后的回调参数
* @param mchApplyment 商户信息, 必须包含完整的数据
* @return
*/
MutablePair<MchApplyment, ResponseEntity> doNotify(HttpServletRequest request, Object params, MchApplyment mchApplyment);
default ResponseEntity<?> retOk(Object params) {
return ResponseEntity.ok(params);
}
}

View File

@@ -0,0 +1,92 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.entity.MchApplyment;
import com.jeequan.jeepay.core.entity.MchSubInfo;
import com.jeequan.jeepay.core.model.applyment.ApplymentBasicInfo;
import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo;
import org.springframework.util.Assert;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/***
* 商户进件接口
*
* @author terrfly
* @date 2021/12/30 11:36
*/
public interface IIsvmchApplymentService<T extends ApplymentBasicInfo> {
ExecutorService executorService = new ThreadPoolExecutor(
10, 80, 60,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(200), new ThreadPoolExecutor.AbortPolicy() // 这里可以选择不同的拒绝策略
);
/** 首次发起进件申请 **/
default MchApplyment firstApplyment(MchApplyment mchApplyment) {
// 直接丢到异步处理进件逻辑, 通用请求可照此逻辑
MchApplyment result = new MchApplyment();
result.setApplyId(mchApplyment.getApplyId());
result.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_AUDITING_WAIT);
result.setRemainStep((byte) 1);
JSONObject jsonObject = JSON.parseObject(mchApplyment.getApplyDetailInfo());
Class<ApplymentBasicInfo> implInfoClass = ApplymentBasicInfo.getImplInfoClass(mchApplyment.getIfCode());
Assert.notNull(implInfoClass, "通道暂不支持");
T applymentBasicInfo = (T) jsonObject.toJavaObject(implInfoClass);
applymentBasicInfo.saveCheck();
result.setSettlementType(applymentBasicInfo.getSettlementType());
return result;
}
/**
* 驳回后的修改接口 (与补充进件进行区分)
* 有的渠道比如中付, 只有接口调起成功即会返回merId 此时不可再次重新发起进件。 如果存在了merId 那么应该需要调起修改补充进件接口。
* 如果不需要区分那么直接内部调用firstApplyment 接口。
*/
MchApplyment rejectModify(MchApplyment mchApplyment);
/** 补充进件资料接口 (此时商户的进件资料应该是已经入驻成功了)
* 调起补充进件资料的流程是: 进件成功--》 资料修改 --》 调起接口(DB不更新) --》 接口响应成功 --> 更新DB资料
* **/
MchApplyment replenishInfo(MchApplyment mchApplyment);
/** 查询审核结果接口 **/
MchApplyment query(MchApplyment mchApplyment);
/** 查询签约合同信息 **/
ApplymentSignInfo signInfo(MchApplyment mchApplyment);
/**
* 合同签约申请, 部分通道入网不需要执行该操作
*/
default MchApplyment signApply(MchApplyment mchApplyment) {
return mchApplyment;
}
default void subMchColl(MchApplyment mchApplyment) {
}
default void subMchColl(MchApplyment mchApplyment, Object callback) {
}
default void subMchCert(MchApplyment mchApplyment, MchSubInfo mchSubInfo) {
}
/** 作废, 商户信息作废,部分通道支持 */
default void cancel(MchApplyment mchApplyment) {
}
}

View File

@@ -0,0 +1,57 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.alibaba.fastjson.JSON;
import com.jeequan.jeepay.core.entity.MchApplyment;
import com.jeequan.jeepay.core.entity.MchModifyApplyment;
import com.jeequan.jeepay.core.model.applyment.MchModifyApplymentModel;
import org.apache.commons.lang3.tuple.MutablePair;
public interface IIsvmchModifyApplymentService {
/**
* 本地基本信息变更
*/
MutablePair<MchModifyApplyment, MchApplyment> localModifyBase(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair);
/**
* 本地结算信息变更
*/
MutablePair<MchModifyApplyment, MchApplyment> localModifySettlement(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair);
/**
* 本地结算信息变更
*/
MutablePair<MchModifyApplyment, MchApplyment> localModifyRate(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair);
default MutablePair<MchModifyApplyment, MchApplyment> localModifySettlementType(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair) {
String applyDetailInfo = mchDataPair.left.getApplyDetailInfo();
MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class);
mchDataPair.right.setSettlementType(mchModifyData.getSettlementType());
mchDataPair.left.setState(MchApplyment.STATE_SUCCESS);
return mchDataPair;
}
/**
* 基本信息变更, 上游通道同步
*/
MutablePair<MchModifyApplyment, MchApplyment> syncChannelModifyBase(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair);
/**
* 结算信息变更, 上游通道同步
*/
MutablePair<MchModifyApplyment, MchApplyment> syncChannelModifySettlement(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair);
/**
* 费率变更, 上游通道同步
*/
MutablePair<MchModifyApplyment, MchApplyment> syncChannelModifyRate(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair);
/**
* 结算方式变更,上游通道同步
*
*/
MutablePair<MchModifyApplyment, MchApplyment> syncChannelModifySettlementType(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair);
MutablePair<MchModifyApplyment, MchApplyment> queryModifyResult(MutablePair<MchModifyApplyment, MchApplyment> mchDataPair);
}

View File

@@ -0,0 +1,27 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import javax.servlet.http.HttpServletRequest;
/**
* 特约商户 门店入驻回调
*
* @author xiaoyu
*
* @date 2022/3/25 16:35
*/
public interface IIsvmchStoreApplymentNotifyService {
/** 通知类型 **/
enum NoticeTypeEnum {
DO_RETURN, //同步跳转
DO_NOTIFY //异步回调
}
/** 获取到接口code **/
String getIfCode();
/** 返回需要更新的订单状态 和响应数据 **/
ChannelRetMsg doNotice(HttpServletRequest request, String storeNo, String isvNo, IIsvmchStoreApplymentNotifyService.NoticeTypeEnum noticeTypeEnum);
}

View File

@@ -0,0 +1,24 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.entity.MchApplyment;
import com.jeequan.jeepay.core.entity.MchStore;
/**
* 特约商户 门店入驻
*
* @author xiaoyu
*
* @date 2022/3/25 16:35
*/
public interface IIsvmchStoreApplymentService {
/** 门店发起入驻 **/
MchApplyment firstStoreApplyment(MchApplyment mchApplyment, MchStore mchStore);
/** 门店修改入驻信息 **/
MchApplyment storeApplymentModify(MchApplyment mchApplyment, MchStore mchStore, JSONObject reqJson);
/** 门店信息查询 **/
MchApplyment storeApplymentQuery(MchApplyment mchApplyment);
}

View File

@@ -0,0 +1,26 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.MchStoreTerminal;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
/***
* 特约商户 设备报备 or 注销
* http://www.gov.cn/zhengce/zhengceku/2022-02/25/content_5675558.htm
* 2021年10月13日中国人民银行发布了《中国人民银行关于加强支付受理终端及相关业务管理的通知》银发2021259号以下简称《通知》自2022年3月1日起施行。
* 2.条码支付辅助受理终端管理。对于仅具备条码读取或展示功能、不参与发起支付指令的条码支付扫码设备、显码设备和静态条码展示介质等条码支付辅助受理终端收单机构应当建立特约商户编码与下述4要素信息的关联对应关系并确保该关联对应关系在支付全流程中的一致性和不可篡改性
* 1收单机构代码
* 2特约商户统一社会信用代码
* 3特约商户收单结算账户
* 4条码支付辅助受理终端布放地理位置。
*
* @author terrfly
*
* @date 2022/04/29 14:52
*/
public interface IIsvmchTerminalService {
/** 设备的报备 or 注销 **/
ChannelRetMsg sendup(MchStoreTerminal mchStoreTerminal, String isvNo, String mchNo, String mchAppId, String ifCode, boolean isSendup);
}

View File

@@ -0,0 +1,15 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.MchApplyment;
/**
* 商户数据包装类,用于做数据转换
*/
public interface IIsvmchWrapper {
/**
* 处理费率信息,缺省参数添加默认值
* @param mchApplyment 商户信息
*/
void rateWrap(MchApplyment mchApplyment);
}

View File

@@ -0,0 +1,43 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.MchApplyment;
import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo;
import com.jeequan.jeepay.core.model.applyment.PaywayFee;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import java.util.List;
/***
* 特约商户 微信配置项
*
* @author terrfly
*
* @date 2022/01/17 09:52
*/
public interface IIsvmchWxConfigService {
/** 查询已经配置的支付参数 **/
String queryConfiguredInfo(String isvNo, String mchNo, String mchAppId, String ifCode);
/** 绑定微信appId **/
ChannelRetMsg configBindAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode);
/** 设置关注公众号appId **/
ChannelRetMsg configSubscribeAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode);
/** 申请更改: 商户简称的配置 **/
ChannelRetMsg applyModifyMchShortName(String mchShortName, String isvNo, String mchNo, String mchAppId, String ifCode);
/** 申请更改: 商户简公钥 **/
ChannelRetMsg applyModifyMchAppPublicKey(String appPublicKey, String isvNo, String mchNo, String mchAppId, String ifCode);
/** 微信开户意愿查询 **/
ApplymentSignInfo wxOpenSignInfo(MchApplyment mchApplyment);
/** 设置微信 支付授权目录 **/
ChannelRetMsg configPayBaseUrl(String configBaseUrl, String isvNo, String mchNo, String mchAppId, String ifCode);
/** 申请更改: 支付费率申请 **/
ChannelRetMsg applyModifyMchRate(List<PaywayFee> paywayFeeList, String isvNo, String mchNo, String mchAppId, String ifCode);
}

View File

@@ -0,0 +1,16 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.MchApplyment;
/**
* 乐刷 进件接口
*
* @author yr
*
* @date 2022/6/9 9:26
*/
public interface ILeshuaApplymentApiService {
/** 开通业务 **/
MchApplyment leshuapayConfigOpen(MchApplyment mchApplyment);
}

View File

@@ -0,0 +1,48 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchApplyment;
import com.jeequan.jeepay.core.model.applyment.PaywayFee;
import com.jeequan.jeepay.core.model.params.IsvParams;
import com.jeequan.jeepay.core.model.rqrs.mch.ChannelMchRq;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.core.model.rqrs.settle.ChannelSettleRq;
import org.apache.commons.lang3.tuple.MutablePair;
import java.util.List;
import java.util.Map;
/**
* TODO
* 商户操作接口定义 用于处理商户在通道方的一些接口定义 例如 新增appid 支付授权目录
* @author crystal
* @date 2023/12/4 10:34
*/
public interface IMchApiService<T extends IsvParams> {
/** 获取到接口code **/
String getIfCode();
/**
* 前置参数校验
* @return
*/
boolean preCheck();
/**
* appid和支付授权目录相关操作
* @param applyment
* @param mchRq
* @return
*/
ChannelRetMsg appidAndPath(MchApplyment applyment, ChannelMchRq mchRq);
/**
* 查询商户结算记录
* @param settleRq
* @return
*/
List<JSONObject> querySettleInfo(ChannelSettleRq settleRq, String isvNo, T isvParams);
}

View File

@@ -0,0 +1,18 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
/**
*
* 商户自主授权响应结果参数 (当前只有支付宝有该接口)
* @author terrfly
*
* @date 2021/12/23 16:47
*/
public interface IMchAutoAuthService {
/** 授权获取参数 **/
JSONObject mchAuth(MchAppConfigContext mchAppConfigContext, String appAuthCode);
}

View File

@@ -0,0 +1,19 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
/**
* 关闭订单(渠道侧)接口定义
*
* @author xiaoyu
*
* @date 2022/1/24 17:23
*/
public interface IPayOrderCloseService {
/** 查询订单 **/
ChannelRetMsg close(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception;
}

View File

@@ -0,0 +1,19 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
/**
* 查单(渠道侧)接口定义
*
* @author terrfly
*
* @date 2021/5/19 15:16
*/
public interface IPayOrderQueryService {
/** 查询订单 **/
ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception;
}

View File

@@ -0,0 +1,16 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
/**
* 项目拆分, 给zft单独加的接口 = =。
* TODO 需要整改!!! 与渠道sdk打交道一定不要跟DB层打交道。 这里只返回成功,或者异常。 所有的业务全部抛到外层处理。
* 若业务代码有冗余需要封装一层service或manager
*
* **/
public interface IPayOrderSettService {
public ChannelRetMsg tradeSettleConfirm(PayOrder payOrder, String alipayTradeNo,String settleNo);
}

View File

@@ -0,0 +1,32 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.rqrs.AbstractRS;
import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ;
/*
* 调起上游渠道侧支付接口
*
* @author terrfly
*
* @date 2021/5/8 15:13
*/
public interface IPaymentService {
/** 获取到接口code **/
String getIfCode();
/** 获取实际使用接口code一般用于克隆接口查询支付参数 **/
String getIfCode(PayOrder payOrder);
/** 是否支持该支付方式 */
boolean isSupport(String wayCode);
/** 前置检查如参数等信息是否符合要求, 返回错误信息或直接抛出异常即可 */
String preCheck(UnifiedOrderRQ bizRQ, PayOrder payOrder);
/** 调起支付接口,并响应数据; 内部处理普通商户和服务商模式 **/
AbstractRS pay(UnifiedOrderRQ bizRQ, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception;
}

View File

@@ -0,0 +1,34 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.entity.RefundOrder;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import org.apache.commons.lang3.tuple.Triple;
import javax.servlet.http.HttpServletRequest;
/*
* 渠道侧的订单通知解析实现 【支付通知payNotice和退款通知(refundNotice) 】
*
* @author zx
*
* @date 2021/5/8 15:14
*/
public interface IPosNoticeService {
/** 获取到接口code **/
String getIfCode();
/** 解析参数:
* 异常需要自行捕捉并返回null , 表示已响应数据。
* **/
Triple<String, String, Object> parseParams(HttpServletRequest request);
/** 返回需要插入的支付订单金额 和响应数据 **/
ChannelRetMsg payNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext);
/** 返回需要插入的退款订单金额 和响应数据 **/
ChannelRetMsg refundNotice(HttpServletRequest request, Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext);
}

View File

@@ -0,0 +1,43 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.entity.RefundOrder;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRefundLimit;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.core.model.rqrs.refund.RefundOrderRQ;
/*
* 调起上游渠道侧退款接口
*
* @author terrfly
*
* @date 2021/6/17 9:35
*/
public interface IRefundService {
/** 获取到接口code **/
String getIfCode();
/** 获取实际使用接口code一般用于克隆接口查询支付参数 **/
String getIfCode(RefundOrder refundOrder);
/** 前置检查如参数等信息是否符合要求, 返回错误信息或直接抛出异常即可 */
String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder);
/** 调起退款接口,并响应数据; 内部处理普通商户和服务商模式 **/
ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception;
/** 退款查单接口 **/
ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception;
/**
* 退款权限判断
* @param settleType
* @param applyId
* @return
*/
ChannelRefundLimit isRefundLimit(String settleType,String applyId);
void checkPlatAccount(RefundOrder refundOrder);
}

View File

@@ -0,0 +1,78 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.CashoutRecord;
import com.jeequan.jeepay.core.model.DBPaymentConfig;
import com.jeequan.jeepay.core.model.df.Account;
import com.jeequan.jeepay.core.model.df.PaymentSign;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
/**
* TODO
* 代付接口
* @author crystal
* @date 2024/3/22 18:02
*/
public interface IRepayApiService {
/** 获取到接口code **/
String getIfCode();
/**
* 是否需要签约
* @return
*/
boolean isSign();
/**
* 前置校验
*/
void preCheck(String mchNo,byte accountType,Long changeAmt);
/**
* 查询账户余额
* @param mchNo 用户号
* @param accountType 账户类型
* @return
*/
Account queryAccountBalance(String mchNo, byte accountType);
/**
* 签约
* @param sign
* @param config
* @return
*/
ChannelRetMsg sign(PaymentSign sign, DBPaymentConfig config);
/**
* 查询签约结果
* @param sign
* @param config
* @return
*/
ChannelRetMsg querySign(PaymentSign sign, DBPaymentConfig config);
/**
* 付款
* @param record
* @param config
* @return
*/
ChannelRetMsg payment(CashoutRecord record, DBPaymentConfig config);
/**
* 付款结果查询
* @param outBizNo 外部请求流水号
* @param config
* @return
*/
ChannelRetMsg queryPayment(String outBizNo, DBPaymentConfig config);
/**
* 校验账户余额
* @param mchNo
* @param accountType
* @param changeAmt
*/
void checkAccountBalance(String mchNo,byte accountType,Long changeAmt);
}

View File

@@ -0,0 +1,28 @@
package com.jeequan.jeepay.core.interfaces.paychannel;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.http.ResponseEntity;
import javax.servlet.http.HttpServletRequest;
/**
* 渠道打款通知
*/
public interface IRepayNoticeService {
/** 获取到接口code **/
String getIfCode();
/** 解析参数: 订单号 和 请求参数
* 异常需要自行捕捉并返回null , 表示已响应数据。
* **/
MutablePair<String, Object> parseParams(HttpServletRequest request, String urlOrderId);
/** 处理参数业务逻辑 **/
ChannelRetMsg doNotice(HttpServletRequest request,String urlOrderId,Object params);
}

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